微信并没有给ASP.net用户提供一个很好的实例,只好苦心研究,经过一个下午的努力和N次测试,终于知道如何解密和验签notify的数据了,以下是我实现的代码,好东西需分享给各位朋友:(以下的商户编号我已经修改过,所以没有返回true,请根据自己的实际数据测试)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing.Drawing2D;
using Ganxike.Bll;
using Ganxike.Entity;
using System.Text;
using System.Security.Cryptography;
namespace Ganxike.Front
{
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//bank_billno:201407013021057579
//bank_type:2011 //付款银行代号
//discount:0 //折扣价格(如果有)
//fee_type:1 //币种
//input_charset:GBK //编码字符
//notify_id:cEBCIhJpi4A6JrwjzYjarrY4-y04msE2T7Ixq0U19wcntbPlOXrtshGlKcEhGsN-uC78fnIcPi6mIFpl2UfDxW3R1yPv7yRQ //通知ID
//out_trade_no:2033179023 //商户订单号
//partner:1218656301 //商户号
//product_fee:1 //物品费用(分)
//sign:24897219B33E59DC7FA49FEC3CE0D1C3 //签名
//sign_type:MD5 //签名方式
//time_end:20140701145333 //支付完成时间
//total_fee:1 //总金额(分)
//trade_mode:1 //交易模式(1即时到帐)
//trade_state:0 //交易状态(0成功)
//transaction_id:1218656301201407013164175338 //订单号
//transport_fee:0 //物流费用
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("bank_billno", "201407013021057579");
parameters.Add("bank_type", "2011");
parameters.Add("discount", "0");
parameters.Add("fee_type", "1");
parameters.Add("input_charset", "GBK");
parameters.Add("notify_id", "cEBCIhJpi4A6JrwjzYjarrY4-y04msE2T7Ixq0U19wcntbPlOXrtshGlKcEhGsN-uC78fnIcPi6mIFpl2UfDxW3R1yPv7yRQ");
parameters.Add("out_trade_no", "2033179023");
parameters.Add("partner", "1218656301");
parameters.Add("product_fee", "1");
parameters.Add("sign_type", "MD5");
parameters.Add("time_end", "20140701145333");
parameters.Add("total_fee", "1");
parameters.Add("trade_mode", "1");
parameters.Add("trade_state", "0");
parameters.Add("transaction_id", "1218656301201407013164175338");
parameters.Add("transport_fee", "0");
//将所有参数按Key字母排序
string content = GetSignContent(parameters);
Response.Write(VerifySignature(content, "24897219BABCDC7FA49DECE0D1C3", "20a01775b1234714920a47a6321cb292"));
}
/// <summary>
/// 验证签名
/// </summary>
/// <param name="content">排序后的所有参数(不包括sign参数)</param>
/// <param name="sign">合作商传过来的sign签名(对参数加密后的MD5)</param>
/// <param name="ourKey">我们用于签名的密钥(用于解密的一串字符)</param>
/// <returns></returns>
public static bool VerifySignature(String content, String sign, String ourKey)
{
string signResult = WXPayMD5(content + "&key=" + ourKey).ToUpper();
return (sign == signResult);
}
/// <summary>
/// MD5加密
/// </summary>
/// <param name="s">需加密的字符</param>
/// <returns></returns>
public static String WXPayMD5(String s)
{
char[] hexDigits = { \'0\', \'1\', \'2\', \'3\', \'4\', \'5\', \'6\', \'7\', \'8\', \'9\',\'A\', \'B\', \'C\', \'D\', \'E\', \'F\' };
try
{
byte[] btInput = System.Text.Encoding.Default.GetBytes(s);
// 获得MD5摘要算法的 MessageDigest 对象
MD5 mdInst = System.Security.Cryptography.MD5.Create();
// 使用指定的字节更新摘要
mdInst.ComputeHash(btInput);
// 获得密文
byte[] md = mdInst.Hash;
// 把密文转换成十六进制的字符串形式
int j = md.Length;
char[] str = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++)
{
byte byte0 = md[i];
str[k++] = hexDigits[(int)(((byte)byte0) >> 4) & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new string(str);
}
catch (Exception e)
{
Console.Error.WriteLine(e.StackTrace);
return null;
}
}
/// <summary>
/// 将字典所有值按Key字母顺序合并成字符串
/// </summary>
/// <param name="parameters">字典类</param>
/// <returns>字符串</returns>
public static string GetSignContent(IDictionary<string, string> parameters)
{
// 第一步:把字典按Key的字母顺序排序
IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
// 第二步:把所有参数名和参数值串在一起
StringBuilder query = new StringBuilder("");
while (dem.MoveNext())
{
string key = dem.Current.Key;
string value = dem.Current.Value;
if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
{
query.Append(key).Append("=").Append(value).Append("&");
}
}
string content = query.ToString().Substring(0, query.Length - 1);
return content;
}
}
}