通过认真查看微信提供的加密类WXBizMsgCrypt.cs,终于找到生成msg_signature的方法,并提取出来,用于模拟微信接口的时候自动生成msg_signature,提取结果如下:
/// <summary> /// 计算出msg_Signature /// </summary> /// <param name="sToken"></param> /// <param name="sTimeStamp"></param> /// <param name="sNonce"></param> /// <param name="sMsgEncrypt"></param> /// <returns></returns> public static string GetSignature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt) { ArrayList AL = new ArrayList(); AL.Add(sToken); AL.Add(sTimeStamp); AL.Add(sNonce); AL.Add(sMsgEncrypt); AL.Sort(new DictionarySort()); string raw = ""; for (int i = 0; i < AL.Count; ++i) { raw += AL[i]; } SHA1 sha; ASCIIEncoding enc; string hash = ""; sha = new SHA1CryptoServiceProvider(); enc = new ASCIIEncoding(); byte[] dataToHash = enc.GetBytes(raw); byte[] dataHashed = sha.ComputeHash(dataToHash); hash = BitConverter.ToString(dataHashed).Replace("-", ""); hash = hash.ToLower(); return hash; } public class DictionarySort : System.Collections.IComparer { public int Compare(object oLeft, object oRight) { string sLeft = oLeft as string; string sRight = oRight as string; int iLeftLength = sLeft.Length; int iRightLength = sRight.Length; int index = 0; while (index < iLeftLength && index < iRightLength) { if (sLeft[index] < sRight[index]) return -1; else if (sLeft[index] > sRight[index]) return 1; else index++; } return iLeftLength - iRightLength; } } /// <summary> /// 获得消息创建时间 /// </summary> /// <returns></returns> public static string GetCreateTime() { int v =Convert.ToInt32( DateTime.Now.Subtract(new DateTime(1970, 1, 1, 8, 0, 0)).TotalSeconds); return v.ToString(); } /// <summary> /// 获得随机数Nonce /// </summary> /// <returns></returns> public static string GetNonce() { Random rd = new Random(Guid.NewGuid().GetHashCode()); int Length = rd.Next(5, 10);//随机长度 string Nonce = String.Empty; //生成第一位随机数,第一位不能是0, Nonce += rd.Next(1, 9).ToString(); for (int i = 1; i < Length; i++) { Nonce += rd.Next(0, 9).ToString(); } return Nonce; }
有了这个方法我们就可以真正的做出模拟了,(之前模拟回调要从微信回调把参数取出来手动填写,现在不需要了,全部自动生成)
修改界面如下:
第一部分一样需要自己填写,2,3,4修改为只读属性,不必用户在自己填写,系统自动生成,
如果4中的随机字符串等于回调结果的字符串,则表示回调认证成功!
按钮1.生成回调参数的方法如下:
WXBizMsgCryptAPI类继承自微信的加密类库WXBizMsgCrypt,代码如下:
public class URLParam { public string timestamp { get; set; } public string nonce { get; set; } public string msg_signature { get; set; } } public class WXBizMsgCryptAPI : WXBizMsgCrypt { URLParam CurrentURLParam; public WXBizMsgCryptAPI(string sCorpToken, string sEncodingAESKey, string sCorpID) : base(sCorpToken, sEncodingAESKey, sCorpID) { CurrentURLParam = new URLParam(); } #region 生成回调各参数及其XML /// <summary> /// 解密获取的结果 /// </summary> /// <param name="Result"></param> /// <returns></returns> public string APIResultHandler(string Result) { XmlDocument CBdoc = new XmlDocument(); XmlNode CBroot; CBdoc.LoadXml(Result); CBroot = CBdoc.FirstChild; string CBsEncryptMsg = CBroot["Encrypt"].InnerText; string CBMsgSignature = CBroot["MsgSignature"].InnerText; string CBTimeStamp = CBroot["TimeStamp"].InnerText; string CBNonce = CBroot["Nonce"].InnerText; string DecResult = ""; int i = DecryptMsg(CBMsgSignature, CBTimeStamp, CBNonce, Result, ref DecResult); if (i == 0) { return DecResult; } else { return i.ToString(); } } /// <summary> /// 微信发送消息参数准备,返回timestamp,nonce,msg_singature /// </summary> /// <param name="msg">需要发送的消息</param> /// <param name="Data">加密后的消息</param> public URLParam APIEncryptMsg(string msg, ref string Data) { //刷新一组随机数 CurrentURLParam.timestamp = CommonTools.GetCreateTime(); CurrentURLParam.nonce = CommonTools.GetNonce(); string sData = ""; string msg_Signature = ""; //加密消息并返回新的msg_signature APIEncryptMsg(msg, CurrentURLParam.timestamp, CurrentURLParam.nonce, ref sData, ref msg_Signature);//加密并获得Sign //记录新的msg_Signature CurrentURLParam.msg_signature = msg_Signature; Data = sData; return CurrentURLParam; } /// <summary> /// 加密消息并返回新的msg_signature /// </summary> /// <param name="msg">需要发送(加密)的数据,微信规定,发送数据前先进行加密处理</param> /// <param name="Data">返回加密后的XML</param> /// <param name="msg_Signature">返回新的msg_Signature</param> /// <returns></returns> private int APIEncryptMsg(string msg, string timestamp, string Nonce, ref string Data, ref string msg_Signature) { int i = EncryptMsg(msg, timestamp, Nonce, ref Data); XmlDocument doc = new XmlDocument(); XmlNode root; string sEncryptMsg; if (i == 0)//刷新signature { doc.LoadXml(Data); root = doc.FirstChild; sEncryptMsg = root["Encrypt"].InnerText; msg_Signature = CommonTools.GetSignature(m_sToken, timestamp, Nonce, sEncryptMsg); } return i; } /// <summary> /// 获得Encrypt节点 /// </summary> /// <param name="EncryXMLData">通过加密后的XML格式数据</param> /// <returns></returns> public string APIGetEncrypt(string EncryXMLData) { XmlDocument doc = new XmlDocument(); XmlNode root; string sEncryptMsg; doc.LoadXml(EncryXMLData); root = doc.FirstChild; sEncryptMsg = root["Encrypt"].InnerText; return sEncryptMsg; } #endregion }
GetEncryptXML()方法代码:
void GetEncryptXML(string msg, ref string sMsg_EncryptMsg) { var v = GenerateData.APIEncryptMsg(msg, ref sMsg_EncryptMsg); //记录生成的URL参数 txt_msg_signature.Text = v.msg_signature; txt_timestamp.Text = v.timestamp; txt_nonce.Text = v.nonce; }
按钮事件:
//获取参数按钮事件 private void btn_msg_signature_Click(object sender, EventArgs e) { //先随机生成一个字符串用于回调验证 string msg = Guid.NewGuid().ToString().Replace("-", ""); txt_Msg.Text = msg; string Msg_EncryptMsg = "";//加密后的数据 GetEncryptXML(msg, ref Msg_EncryptMsg); string Encrypt = GenerateData.APIGetEncrypt(Msg_EncryptMsg); //获取到加密后XML的Encrypt节点,URL编码后以Get方式提交 txt_echostr.Text = System.Web.HttpUtility.UrlEncode(Encrypt); }
GenerateData是WXBizMsgCryptAPI的一个实例
按钮2,(2.本地回调,请在本地断点调试)的事件代码如下
//微信首次回调验证按钮事件 private void btn_CallBackValidate_Click(object sender, EventArgs e) { string URL = GenerateValidationURL(); txt_ValidURL.Text = URL; if (String.IsNullOrEmpty(URL)) return; txt_ValidBackData.Text = CommonTools.GetWebData(URL); }
本节完成!
开源项目地址:https://github.com/GarsonZhang/QYWXLocalDebug/
日志列表: