要求
- 首先,排除sign参数之外,将其它参数(空值除外)按名称进行字母排序,并和它的取值一起组成name=value样式的字符串,然后用&把它们拼装为一个大字符串,对于嵌套的参数,嵌套的参数列表也需按照字母排序进行拼装。
a) 比如,要传递下列参数
i.version=1.0.0
ii.return_code=0
iii.拼装之后的字符串为:return_code=0&version=1.0.0
b) 比如,要传递下列参数
i.a=1
ii.b={“d”:”3”,”c”:”2”}
iii.拼装之后的字符串为:a=1&b=c=2&d=3
c)比如,要传递下列参数
i.a=1
ii.b=[{“d”:”3”,”c”:”2”},{“d”:”5”,”c”:”4”}]
iii.拼装之后的字符串为:a=1&b=c=2&d=3&c=4&d=5
d)比如,要传递下列参数
i.a=1
ii.b=[“2”,”3”]
iii.拼装之后的字符串为:a=1&b=2&3
e)比如,要传递下列参数
i.a=1
ii.b=[[{“d1”:”1”,”c1”:”2”},{“d2”:”3”,”c2”:”4”}],[{“d3”:”5”,”c3”:”6”},{“d4”:”7”,”c4”:”8”}]]
iii.拼装之后的字符串为:a=1&b=c1=2&d1=1&c2=4&d2=3&c3=6&d3=5&c4=8&d4=7- 在上述拼装之后的字符串后面直接拼装accesskey的值。
a)比如,上述参数return_code=0&version=1.0.0,假设accesskey是123456789ABCDEF,拼装以后,成为下述字符串:
b)return_code=0&version=1.0.0123456789ABCDEF- 对上述第2步得到的字符串,进行MD5运算(32位大写),得到sign
using Newtonsoft.Json;using Newtonsoft.Json.Linq;using System.Security.Cryptography;using System.Text;namespace Demo{public class SignUtils{private static readonly JsonSerializerSettings jSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Include };public static string GetToBeSign(SortedDictionary<string, object> dictionary){var json = JsonConvert.SerializeObject(dictionary, jSetting);var jobj = JsonConvert.DeserializeObject<JObject>(json);return GetToBeSign(jobj);}public static string GetToBeSign(string json){var jobj = JsonConvert.DeserializeObject<JObject>(json);return GetToBeSign(jobj);}public static string GetToBeSign(JObject jobj){var _dictionary = new SortedDictionary<string, string>();foreach (var item in jobj){if (item.Value == null || "".Equals(item.Value) || "".Equals(item.Value.ToString()) || "sign".Equals(item.Key) || "mac".Equals(item.Key)){continue;}var value = item.Value.ToString();if (item.Value.GetType() == typeof(JObject)){value = GetToBeSign(value);}else if (item.Value.GetType() == typeof(JArray)){value = GetJsonArrayStr(value);}_dictionary.Add(item.Key, value);}var values = _dictionary.OrderBy(o => o.Key).Select(s => $"{s.Key}={s.Value}");return string.Join("&", values);}public static string GetJsonArrayStr(string jarrstr){var jarr = JsonConvert.DeserializeObject<JArray>(jarrstr);return GetJsonArrayStr(jarr);}public static string GetJsonArrayStr(JArray jarr){var values = new List<string>();foreach (var item in jarr){var value = item.ToString();if (item.GetType() == typeof(JObject)){value = GetToBeSign(item.ToString());}else if (item.GetType() == typeof(JArray)){value = GetJsonArrayStr(item as JArray);}values.Add(value);}return string.Join("&", values);}/// <summary>/// 使用 MD5 对输入字符串进行加密/// </summary>/// <param name="inputString">需要加密的字符串</param>/// <param name="charset">编码格式</param>/// <returns>返回加密后的字符串</returns>private static string ConvertToMD5(string inputString, string charset = null){if (string.IsNullOrEmpty(charset)){charset = "utf-8";}MD5 md5Hash = MD5.Create();byte[] bytes = md5Hash.ComputeHash(Encoding.GetEncoding(charset).GetBytes(inputString));StringBuilder result = new StringBuilder();foreach (byte b in bytes){result.Append(b.ToString("x2"));}return result.ToString();}public static string Sign(string json, string key){var tobesign = $"{GetToBeSign(json)}{key}";var sign = ConvertToMD5(tobesign).ToUpper();return sign;}public static string Sign(SortedDictionary<string, object> dictionary, string key){var tobesign = $"{GetToBeSign(dictionary)}{key}";var sign = ConvertToMD5(tobesign).ToUpper();return sign;}public static bool CheckSign(string json, string key){var param = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);var ispassed = param.TryGetValue("sign", out object originsign);if (!ispassed) { return !ispassed; }var tobesign = $"{GetToBeSign(json)}{key}";var sign = ConvertToMD5(tobesign).ToUpper();return originsign.ToString() == sign;}}}
