(转) 用API接口签名验证参考
项目中常用的API接口签名验证方法:
1. 给app分配对应的key、secret
2. Sign签名,调用API 时需要对请求参数进行签名验证,签名方式如下:
a. 按照请求参数名称将所有请求参数按照字母先后顺序排序得到:keyvaluekeyvalue...keyvalue 字符串如:将arong=1,mrong=2,crong=3 排序为:arong=1, crong=3,mrong=2 然后将参数名和参数值进行拼接得到参数字符串:arong1crong3mrong2;
b. 将secret加在参数字符串的头部后进行MD5加密 ,加密后的字符串需大写。即得到签名Sign;
大致处理过程
// 用户验证、判断key是否存在,同时查询出对应的secret用于验证;
....
// 验证签名,根据算法将参数进行签名得到sign与参数中的sign进行对比;
....
// 插叙数据获取列表
如下图

app调用:http://api.test.com/getproducts?key=app_key&sign=BCC7C71CF93F9CDBDB88671B701D8A35&参数1=value1&参数2=value2.......
注:secret 仅作加密使用, 为了保证数据安全请不要在请求参数中使用。
请求的唯一性: 为了防止别人重复使用请求参数问题,我们需要保证请求的唯一性,就是对应请求只能使用一次,这样就算别人拿走了请求的完整链接也是无效的。
唯一性的实现:在如上的请求参数中,我们加入时间戳 :timestamp(yyyyMMddHHmmss),同样,时间戳作为请求参数之一,也加入sign算法中进行加密。
下面提供2个签名验证的方法:时间戳注意加入及验证的处理
1、OpenId签名及验证
/// <summary>
/// 生成Code
/// </summary>
/// <param name="openid">openid</param>
/// <param name="key">向谁跳传谁规定的key</param>
/// <returns></returns>
public static string MakeCode(string openid, string key)
{
DateTime time = DateTime.Now;
string data = time.ToString("dd") + "_" + openid + "_" + time.ToString("yyyy") + "_" + key + "_" + time.ToString("MM");
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = Encoding.Default.GetBytes(data);
byte[] output = md5.ComputeHash(result);
data = BitConverter.ToString(output).Replace("-", "").ToLower();
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
byte[] bytes = sha1.ComputeHash(Encoding.ASCII.GetBytes(data));//"596d42faf5710b35c7ea0f0a9600ee31" F69D39E1CA07FC23C1CE62F549E9D5B9780
//转16进制 清除前面0
StringBuilder strB = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
string strX2 = bytes[i].ToString("X2");
if (strX2.Substring(0, 1) == "0")
{
strX2 = strX2.Substring(1, 1);
}
strB.Append(strX2);
}
return strB.ToString();
}
/// <summary>
/// Code验证
/// </summary>
/// <param name="openid">openid</param>
/// <param name="code">待验证的数据</param>
/// <param name="key">自己系统规定的key</param>
/// <returns></returns>
public static bool ValidateCode(string openid, string code, string key)
{
string signedData = MakeCode(openid, key);
return code.Equals(signedData, StringComparison.OrdinalIgnoreCase);
}
2、请求参数签名及验证
/// <summary>
/// 给请求签名
/// </summary>
/// <param name="parameters">所有字符型的请求参数</param>
/// <param name="secret">签名密钥</param>
/// <param name="qhs">是否前后都加密进行签名</param>
/// <returns></returns>
public string SignRequest(IDictionary<string, string> parameters, string secret, bool qhs)
{
// 第一步:把字典按Key的字母顺序排序
IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
// 第二步:把所有参数名和参数值串在一起
StringBuilder query = new StringBuilder(secret);
while (dem.MoveNext())
{
string key = dem.Current.Key;
string value = dem.Current.Value;
if (!string.IsNullOrWhiteSpace(key))//!string.IsNullOrWhiteSpace(value) 空值也加入计算??
{
query.Append(key).Append(value);
}
}
if (qhs)
{
query.Append(secret);
}
// 第三部:使用md5运算
MD5 md5 = MD5.Create();
byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(query.ToString()));
// 第四部:把二进制转为大写的十六进制
StringBuilder result = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
result.Append(bytes[i].ToString("X2"));
}
return result.ToString();
}
/// <summary>
/// 验证签名
/// </summary>
/// <returns></returns>
public bool ValidateSign(string secret)
{
string method = HttpContext.Current.Request.HttpMethod;
System.Collections.Specialized.NameValueCollection form = HttpContext.Current.Request.QueryString;
switch (method)
{
case "POST":
form = HttpContext.Current.Request.Form;
break;
case "GET":
form = HttpContext.Current.Request.QueryString;
break;
default:
return false;
}
IDictionary<string, string> parameters = new Dictionary<string, string>();
string sign = string.Empty;
for (int i = 0; i < form.Count; i++)
{
string key = form.Keys[i];
if (string.Equals(key,"sign",StringComparison.OrdinalIgnoreCase))
{
sign = form["sign"];
continue;
}
parameters.Add(key,form[key]);
}
return string.Equals(SignRequest(parameters, secret, false), sign,StringComparison.OrdinalIgnoreCase);
}
一般企业内部应用相互之间接口调用是不需要进行参数的签名验证的,大部分情况下是提供给第三方时才会需要。如果您有更好的接口签名验证方法,欢迎分享~~~


浙公网安备 33010602011771号