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();
}
}
}