要求
- 首先,排除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;
}
}
}