using System; using System.Web; //正则 using System.Text.RegularExpressions; using System.Security.Cryptography; //泛型 using System.Collections.Generic; // 字符相关 using System.Text; namespace HttpProxyWorld { /** * 生成签名类 * * @version 3.0.0 * @author open.qq.com * @copyright © 2012, Tencent Corporation. All rights reserved. * @ History: * 3.0.0 | coolinchen | 2013-1-11 11:11:11 | initialization */ public class SnsSigCheck { public SnsSigCheck() { } /// /// 生成签名 /// /// 请求方法 get/post /// url_path /// 表单参数 /// 密钥 /// 返回签名结果 // static public string MakeSig(string method, string url_path, Dictionaryparam, string secret) { string mk = MakeSource(method, url_path, param); //使用SHA1的HMAC HMAC hmac = HMACSHA1.Create(); hmac.Key = Encoding.UTF8.GetBytes(secret); byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(mk)); //转为base64编码 string my_sign = Convert.ToBase64String(hash); return my_sign; } static private string MakeSource(string method, string url_path, Dictionary param) { string strs = method.ToUpper() + "&" + UrlEncode(url_path, Encoding.UTF8) + "&"; string query_string = ""; List> myList = new List>(param); myList.Sort(delegate(KeyValuePair s1, KeyValuePair s2) { return s1.Key.CompareTo(s2.Key); }); foreach (KeyValuePair pair in myList) { query_string = query_string + pair.Key + "=" + pair.Value + "&"; } query_string = query_string.Substring(0, query_string.Length - 1); query_string = UrlEncode(query_string, Encoding.UTF8); return strs + query_string; } /// ///解决HttpUtility.UrlEncode会将符号编码为小写英文的问题 /// /// 待编码的字符串 /// 编码的方式 /// 返回编码结果 static public string UrlEncode(string temp, Encoding encoding) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < temp.Length; i++) { string t = temp[i].ToString(); string k; switch (t) { case "'": t = "%27"; builder.Append(t); break; case " ": t = "%20"; builder.Append(t); break; case "(": t = "%28"; builder.Append(t); break; case ")": t = "%29"; builder.Append(t); break; case "!": t = "%21"; builder.Append(t); break; case "*": t = "%2A"; builder.Append(t); break; default: k = HttpUtility.UrlEncode(t, encoding); if (t == k) { builder.Append(t); } else { builder.Append(k.ToUpper()); } break; } } return builder.ToString(); } /// ///验证回调发货URL的签名 (注意和普通的OpenAPI签名算法不一样, 详见 ///http://wiki.open.qq.com/wiki/%E5%9B%9E%E8%B0%83%E5%8F%91%E8%B4%A7URL%E7%9A%84%E5%8D%8F%E8%AE%AE%E8%AF%B4%E6%98%8E_V3 /// /// 请求方法 get/post /// url_path /// 腾讯调用发货回调URL携带的请求参数 /// 密钥 /// 腾讯调用发货回调URL时传递的签名 /// 签名校验结果 static public bool VerifySig(string method,string url_path, Dictionary param,string secret,string sig) { // param无需传sig if (param.ContainsKey("sig")) { param.Remove("sig"); } Dictionary new_param = new Dictionary(); // 先使用专用的编码规则对value编码 foreach (string key in param.Keys) { new_param.Add(key, EncodeValue(param[key])); } // 再计算签名 string sig_new = MakeSig(method, url_path, new_param, secret); return sig_new.Equals(sig); } /// ///回调发货URL专用的编码算法 ///编码规则为:除了 0~9 a~z A~Z !*()之外其他字符按其ASCII码的十六进制加%进行表示,例如"-"编码为"%2D" ///详见 http://wiki.open.qq.com/wiki/%E5%9B%9E%E8%B0%83%E5%8F%91%E8%B4%A7URL%E7%9A%84%E5%8D%8F%E8%AE%AE%E8%AF%B4%E6%98%8E_V3 /// /// 待编码的字符串 /// 返回编码结果 static public string EncodeValue(string value) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < value.Length; i++) { if (Regex.IsMatch(value[i].ToString(), @"[a-zA-Z0-9!()*]")) { builder.Append(value[i].ToString()); } else { //byte[] bt = new byte[1]; byte[] bt = Encoding.UTF8.GetBytes(value[i].ToString());//中文的话,一个汉字有三个字节 for (int k = 0; k < bt.Length; k++) { int ascii = (short)(bt[k]);//计算每个字节的ascii码值 builder.Append("%" + Convert.ToString(ascii, 16).ToUpper()); } } } return builder.ToString(); } } }