Unity3D MD5 签名算法实现流程。
MD5 签名算法
之前在和运营对接支付订单模块时,需要向他们的服务器发送查单请求,其中有个参数是 sign,要求把订单的相关信息,转换成 MD5 的形式。
简要流程:
- 先对参数列表按照 ASCII 码排序
- 参数列表拼接成字符串,末尾拼接密钥
- 拼接后的字符串做 MD5 计算
参数列表排序
首先,假设有如下参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| using System.Collections; using System.Collections.Generic; using UnityEngine;
public class TestMD5 : MonoBehaviour { void Start() { Dictionary<string, object> args = new Dictionary<string, object> { ["product_id"] = 100001, ["product_name"] = "金币礼包", ["amount"] = 1, ["price"] = 600 }; } }
|
现在需要先对字典中的参数按照 ASCII 码进行排序。
这里创建一个静态类 MD5Sign.cs
作为工具类使用。
添加方法 AsciiDicToStr
,接收字典类型的参数,返回字符串。
引用 System.Linq
命名空间,可以扩展字典的方法,例如 ToArray,把字典的 key 值取出,变成数组。
利用 Array.Sort
进行排序(需要命名空间 System
),传入参数 string.CompareOrdinal
就可以按照 ASCII 码从小到大进行排序了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| using System; using System.Collections; using System.Collections.Generic; using System.Linq;
public static class MD5Sign { static string AsciiDicToStr(Dictionary<string, object> args) { string[] keysArray = args.Keys.ToArray();
Array.Sort(keysArray, string.CompareOrdinal);
return ""; } }
|
参数拼接字符串
继续扩展 AsciiDicToStr
方法。
引用命名空间 System.Text
,就可以使用 StringBuilder
来拼接字符串了。
遍历 key 数组,按照 key=value&
的形式拼接,参数值为 null 或者 “” 不参与签名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text;
public static class MD5Sign { static string AsciiDicToStr(Dictionary<string, object> args) { string[] keysArray = args.Keys.ToArray();
Array.Sort(keysArray, string.CompareOrdinal);
StringBuilder sb = new StringBuilder();
foreach (var key in keysArray) { string value = args[key]?.ToString();
if (value != null && !string.Empty.Equals(value)) { sb.Append(key); sb.Append("="); sb.Append(value); sb.Append("&"); } }
return sb.ToString(); } }
|
现在可以再添加一个方法 ComputeSign
提供给外部调用。
这里定义了一个密钥,内容是随便输入的,用于演示,通常情况下密钥不会放在客户端,防止被破解获取,应该放到服务端。
调用上面写的 AsciiDicToStr
方法,传入字典,得到 result,在末尾继续拼接 key=signKey
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public static class MD5Sign { static string signKey = "abcdefg";
public static string ComputeSign(Dictionary<string, object> args) { string result = AsciiDicToStr(args);
result += $"key={signKey}";
return result; }
}
|
现在可以先调用这个方法,查看拼接后的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class TestMD5 : MonoBehaviour { void Start() { Dictionary<string, object> args = new Dictionary<string, object> { ["product_id"] = 100001, ["product_name"] = "金币礼包", ["amount"] = 1, ["price"] = 600 };
string result = MD5Sign.ComputeSign(args); Debug.Log($"result = {result}"); } }
|
计算 MD5
在静态类 MD5Sign.cs
中继续添加方法 ComputeStringMD5
,接收字符串,返回字符串。
在 C# 中,有提供用于加密算法的类,需要引用命名空间 System.Security.Cryptography
。
创建一个 MD5 对象,先通过 Encoding.UTF8.GetBytes
方法,把字符串转成 byte 数组,传给 MD5 对象的 ComputeHash
方法,同样得到 byte 数组,遍历这个 byte 数组,使用 ToString("X2")
的格式进行拼接(X2
表示使用大写十六进制,不足两位时前面补 0)。
因为 byte 数组的长度是 16,每个值都转成两位字符串,最终得到的就是 32 位字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| using System.Security.Cryptography;
public static class MD5Sign {
static string ComputeStringMD5(string str) { StringBuilder sb = new StringBuilder();
using (MD5 md5 = MD5.Create()) { byte[] buffer = Encoding.UTF8.GetBytes(str);
byte[] mdBytes = md5.ComputeHash(buffer); md5.Clear();
for (int i = 0; i < mdBytes.Length; i++) { sb.Append(mdBytes[i].ToString("X2")); }
return sb.ToString(); } } }
|
最后把这个方法接入 ComputeSign
方法中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static class MD5Sign { public static string ComputeSign(Dictionary<string, object> args) { string result = AsciiDicToStr(args);
result += $"key={signKey}";
string md5 = ComputeStringMD5(result);
return md5; } }
|
现在调用这个方法就可以得到计算 MD5 之后的结果了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class TestMD5 : MonoBehaviour { void Start() { Dictionary<string, object> args = new Dictionary<string, object> { ["product_id"] = 100001, ["product_name"] = "金币礼包", ["amount"] = 1, ["price"] = 600 };
string result = MD5Sign.ComputeSign(args); Debug.Log($"result = {result}"); } }
|
完整代码
MD5Sign.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography;
public static class MD5Sign { static string signKey = "abcdefg";
public static string ComputeSign(Dictionary<string, object> args) { string result = AsciiDicToStr(args);
result += $"key={signKey}";
string md5 = ComputeStringMD5(result);
return md5; }
static string AsciiDicToStr(Dictionary<string, object> args) { string[] keysArray = args.Keys.ToArray();
Array.Sort(keysArray, string.CompareOrdinal);
StringBuilder sb = new StringBuilder();
foreach (var key in keysArray) { string value = args[key]?.ToString();
if (value != null && !string.Empty.Equals(value)) { sb.Append(key); sb.Append("="); sb.Append(value); sb.Append("&"); } }
return sb.ToString(); }
static string ComputeStringMD5(string str) { StringBuilder sb = new StringBuilder();
using (MD5 md5 = MD5.Create()) { byte[] buffer = Encoding.UTF8.GetBytes(str);
byte[] mdBytes = md5.ComputeHash(buffer); md5.Clear();
for (int i = 0; i < mdBytes.Length; i++) { sb.Append(mdBytes[i].ToString("X2")); }
return sb.ToString(); } } }
|