微信公眾號開發--用.Net Core實現微信消息加解密

来源:https://www.cnblogs.com/NuoYer/archive/2018/01/09/8251329.html
-Advertisement-
Play Games

1、進入微信公眾號後臺設置微信伺服器配置參數(註意:Token和EncodingAESKey必須和微信伺服器驗證參數保持一致,不然驗證不會通過)。 2、設置為安全模式 3、代碼實現(主要分為驗證介面和消息處理介面): 加解密實現(微信公眾號官網有源碼) ...


 

1、進入微信公眾號後臺設置微信伺服器配置參數(註意:Token和EncodingAESKey必須和微信伺服器驗證參數保持一致,不然驗證不會通過)。

2、設置為安全模式

3、代碼實現(主要分為驗證介面和消息處理介面):

 1 /// <summary>
 2 /// 驗證介面
 3 /// </summary>
 4 /// <param name="signature">簽名</param>
 5 /// <param name="timestamp">時間戳</param>
 6 /// <param name="nonce"></param>
 7 /// <param name="echostr"></param>
 8 /// <returns></returns>
 9 [HttpGet, Route("Message")]
10 [AllowAnonymous]
11 public ActionResult MessageGet(string signature, string timestamp, string nonce, string echostr)
12 {
13 if (new SecurityHelper().CheckSignature(signature, timestamp, nonce, _settings.Value.Token))
14 {
15 return Content(echostr);
16 }
17 return Content("");
18 }
19 
20 /// <summary>
21 /// 接收消息並處理和返回相應結果
22 /// </summary>
23 /// <param name="msg_signature">當加密模式時才會有該變數(消息簽名)</param>
24 /// <param name="signature">簽名</param>
25 /// <param name="timestamp">時間戳</param>
26 /// <param name="nonce"></param>
27 /// <returns></returns>
28 [HttpPost, Route("Message")]
29 [AllowAnonymous]
30 public ActionResult MessagePost(string msg_signature, string signature, string timestamp, string nonce)
31 {
32 try
33 {
34 if (!new SecurityHelper().CheckSignature(signature, timestamp, nonce, _settings.Value.Token))
35 {
36 return Content(null);
37 }
38 using (Stream stream = HttpContext.Request.Body)
39 {
40 byte[] buffer = new byte[HttpContext.Request.ContentLength.Value];
41 stream.Read(buffer, 0, buffer.Length);
42 string content = Encoding.UTF8.GetString(buffer);
43 if (!string.IsNullOrWhiteSpace(msg_signature)) // 消息加密模式
44 {
45 string decryptMsg = string.Empty;
46 var wxBizMsgCrypt = new WXBizMsgCrypt(_settings.Value.Token, _settings.Value.EncodingAESKey, _settings.Value.AppId);
47 int decryptResult = wxBizMsgCrypt.DecryptMsg(msg_signature, timestamp, nonce, content, ref decryptMsg);
48 if (decryptResult == 0 && !string.IsNullOrWhiteSpace(decryptMsg))
49 {
50 string resultMsg = new WechatMessageHelper().MessageResult(decryptMsg);
51 string sEncryptMsg = string.Empty;
52 if (!string.IsNullOrWhiteSpace(resultMsg))
53 {
54 int encryptResult = wxBizMsgCrypt.EncryptMsg(resultMsg, timestamp, nonce, ref sEncryptMsg);
55 if (encryptResult == 0 && !string.IsNullOrWhiteSpace(sEncryptMsg))
56 {
57 return Content(sEncryptMsg);
58 }
59 }
60 }
61 }
62 else // 消息未加密碼處理
63 {
64 string resultMsg = new WechatMessageHelper().MessageResult(content);
65 return Content(resultMsg);
66 }
67 return Content(null);
68 }
69 }
70 catch (Exception ex)
71 {
72 _logger.LogError("接收消息並處理和返回相應結果異常:", ex);
73 return Content(null);
74 }
75 }

加解密實現(微信公眾號官網有源碼)

  1 using System;
  2 using System.Collections;
  3 using System.Security.Cryptography;
  4 using System.Text;
  5 using System.Xml;
  6 
  7 //-40001 : 簽名驗證錯誤
  8 //-40002 :  xml解析失敗
  9 //-40003 :  sha加密生成簽名失敗
 10 //-40004 :  AESKey 非法
 11 //-40005 :  appid 校驗錯誤
 12 //-40006 :  AES 加密失敗
 13 //-40007 : AES 解密失敗
 14 //-40008 : 解密後得到的buffer非法
 15 //-40009 :  base64加密異常
 16 //-40010 :  base64解密異常
 17 namespace  Core.Common.Wechat
 18 {
 19     public class WXBizMsgCrypt
 20     {
 21         string m_sToken;
 22         string m_sEncodingAESKey;
 23         string m_sAppID;
 24         enum WXBizMsgCryptErrorCode
 25         {
 26             WXBizMsgCrypt_OK = 0,
 27             WXBizMsgCrypt_ValidateSignature_Error = -40001,
 28             WXBizMsgCrypt_ParseXml_Error = -40002,
 29             WXBizMsgCrypt_ComputeSignature_Error = -40003,
 30             WXBizMsgCrypt_IllegalAesKey = -40004,
 31             WXBizMsgCrypt_ValidateAppid_Error = -40005,
 32             WXBizMsgCrypt_EncryptAES_Error = -40006,
 33             WXBizMsgCrypt_DecryptAES_Error = -40007,
 34             WXBizMsgCrypt_IllegalBuffer = -40008,
 35             WXBizMsgCrypt_EncodeBase64_Error = -40009,
 36             WXBizMsgCrypt_DecodeBase64_Error = -40010
 37         };
 38 
 39         //構造函數
 40         // @param sToken: 公眾平臺上,開發者設置的Token
 41         // @param sEncodingAESKey: 公眾平臺上,開發者設置的EncodingAESKey
 42         // @param sAppID: 公眾帳號的appid
 43         public WXBizMsgCrypt(string sToken, string sEncodingAESKey, string sAppID)
 44         {
 45             m_sToken = sToken;
 46             m_sAppID = sAppID;
 47             m_sEncodingAESKey = sEncodingAESKey;
 48         }
 49 
 50 
 51         // 檢驗消息的真實性,並且獲取解密後的明文
 52         // @param sMsgSignature: 簽名串,對應URL參數的msg_signature
 53         // @param sTimeStamp: 時間戳,對應URL參數的timestamp
 54         // @param sNonce: 隨機串,對應URL參數的nonce
 55         // @param sPostData: 密文,對應POST請求的數據
 56         // @param sMsg: 解密後的原文,當return返回0時有效
 57         // @return: 成功0,失敗返回對應的錯誤碼
 58         public int DecryptMsg(string sMsgSignature, string sTimeStamp, string sNonce, string sPostData, ref string sMsg)
 59         {
 60             if (m_sEncodingAESKey.Length != 43)
 61             {
 62                 return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
 63             }
 64             XmlDocument doc = new XmlDocument();
 65             XmlNode root;
 66             string sEncryptMsg;
 67             try
 68             {
 69                 doc.LoadXml(sPostData);
 70                 root = doc.FirstChild;
 71                 sEncryptMsg = root["Encrypt"].InnerText;
 72             }
 73             catch (Exception)
 74             {
 75                 return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ParseXml_Error;
 76             }
 77             //verify signature
 78             int ret = 0;
 79             ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEncryptMsg, sMsgSignature);
 80             if (ret != 0)
 81                 return ret;
 82             //decrypt
 83             string cpid = "";
 84             try
 85             {
 86                 sMsg = Cryptography.AES_decrypt(sEncryptMsg, m_sEncodingAESKey, ref cpid);
 87             }
 88             catch (FormatException)
 89             {
 90                 return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecodeBase64_Error;
 91             }
 92             catch (Exception)
 93             {
 94                 return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecryptAES_Error;
 95             }
 96             if (cpid != m_sAppID)
 97                 return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateAppid_Error;
 98             return 0;
 99         }
100 
101         //將企業號回覆用戶的消息加密打包
102         // @param sReplyMsg: 企業號待回覆用戶的消息,xml格式的字元串
103         // @param sTimeStamp: 時間戳,可以自己生成,也可以用URL參數的timestamp
104         // @param sNonce: 隨機串,可以自己生成,也可以用URL參數的nonce
105         // @param sEncryptMsg: 加密後的可以直接回覆用戶的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字元串,
106         //                        當return返回0時有效
107         // return:成功0,失敗返回對應的錯誤碼
108         public int EncryptMsg(string sReplyMsg, string sTimeStamp, string sNonce, ref string sEncryptMsg)
109         {
110             if (m_sEncodingAESKey.Length != 43)
111             {
112                 return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
113             }
114             string raw = "";
115             try
116             {
117                 raw = Cryptography.AES_encrypt(sReplyMsg, m_sEncodingAESKey, m_sAppID);
118             }
119             catch (Exception)
120             {
121                 return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_EncryptAES_Error;
122             }
123             string MsgSigature = "";
124             int ret = 0;
125             ret = GenarateSinature(m_sToken, sTimeStamp, sNonce, raw, ref MsgSigature);
126             if (0 != ret)
127                 return ret;
128             sEncryptMsg = "";
129 
130             string EncryptLabelHead = "<Encrypt><![CDATA[";
131             string EncryptLabelTail = "]]></Encrypt>";
132             string MsgSigLabelHead = "<MsgSignature><![CDATA[";
133             string MsgSigLabelTail = "]]></MsgSignature>";
134             string TimeStampLabelHead = "<TimeStamp><![CDATA[";
135             string TimeStampLabelTail = "]]></TimeStamp>";
136             string NonceLabelHead = "<Nonce><![CDATA[";
137             string NonceLabelTail = "]]></Nonce>";
138             sEncryptMsg = sEncryptMsg + "<xml>" + EncryptLabelHead + raw + EncryptLabelTail;
139             sEncryptMsg = sEncryptMsg + MsgSigLabelHead + MsgSigature + MsgSigLabelTail;
140             sEncryptMsg = sEncryptMsg + TimeStampLabelHead + sTimeStamp + TimeStampLabelTail;
141             sEncryptMsg = sEncryptMsg + NonceLabelHead + sNonce + NonceLabelTail;
142             sEncryptMsg += "</xml>";
143             return 0;
144         }
145 
146         public class DictionarySort : System.Collections.IComparer
147         {
148             public int Compare(object oLeft, object oRight)
149             {
150                 string sLeft = oLeft as string;
151                 string sRight = oRight as string;
152                 int iLeftLength = sLeft.Length;
153                 int iRightLength = sRight.Length;
154                 int index = 0;
155                 while (index < iLeftLength && index < iRightLength)
156                 {
157                     if (sLeft[index] < sRight[index])
158                         return -1;
159                     else if (sLeft[index] > sRight[index])
160                         return 1;
161                     else
162                         index++;
163                 }
164                 return iLeftLength - iRightLength;
165 
166             }
167         }
168         //Verify Signature
169         private static int VerifySignature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt, string sSigture)
170         {
171             string hash = "";
172             int ret = 0;
173             ret = GenarateSinature(sToken, sTimeStamp, sNonce, sMsgEncrypt, ref hash);
174             if (ret != 0)
175                 return ret;
176             //System.Console.WriteLine(hash);
177             if (hash == sSigture)
178                 return 0;
179             else
180             {
181                 return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateSignature_Error;
182             }
183         }
184 
185         public static int GenarateSinature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt, ref string sMsgSignature)
186         {
187             ArrayList AL = new ArrayList();
188             AL.Add(sToken);
189             AL.Add(sTimeStamp);
190             AL.Add(sNonce);
191             AL.Add(sMsgEncrypt);
192             AL.Sort(new DictionarySort());
193             string raw = "";
194             for (int i = 0; i < AL.Count; ++i)
195             {
196                 raw += AL[i];
197             }
198 
199             SHA1 sha;
200             ASCIIEncoding enc;
201             string hash = "";
202             try
203             {
204                 sha = new SHA1CryptoServiceProvider();
205                 enc = new ASCIIEncoding();
206                 byte[] dataToHash = enc.GetBytes(raw);
207                 byte[] dataHashed = sha.ComputeHash(dataToHash);
208                 hash = BitConverter.ToString(dataHashed).Replace("-", "");
209                 hash = hash.ToLower();
210             }
211             catch (Exception)
212             {
213                 return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ComputeSignature_Error;
214             }
215             sMsgSignature = hash;
216             return 0;
217         }
218     }
219 }
  1 using System;
  2 using System.IO;
  3 using System.Net;
  4 using System.Security.Cryptography;
  5 using System.Text;
  6 
  7 namespace  Core.Common.Wechat
  8 {
  9     /// <summary>
 10     /// 
 11     /// </summary>
 12     public class Cryptography
 13     {
 14         public static UInt32 HostToNetworkOrder(UInt32 inval)
 15         {
 16             UInt32 outval = 0;
 17             for (int i = 0; i < 4; i++)
 18                 outval = (outval << 8) + ((inval >> (i * 8)) & 255);
 19             return outval;
 20         }
 21 
 22         public static Int32 HostToNetworkOrder(Int32 inval)
 23         {
 24             Int32 outval = 0;
 25             for (int i = 0; i < 4; i++)
 26                 outval = (outval << 8) + ((inval >> (i * 8)) & 255);
 27             return outval;
 28         }
 29         /// <summary>
 30         /// 解密方法
 31         /// </summary>
 32         /// <param name="Input">密文</param>
 33         /// <param name="EncodingAESKey"></param>
 34         /// <returns></returns>
 35         /// 
 36         public static string AES_decrypt(String Input, string EncodingAESKey, ref string appid)
 37         {
 38             byte[] Key;
 39             Key = Convert.FromBase64String(EncodingAESKey + "=");
 40             byte[] Iv = new byte[16];
 41             Array.Copy(Key, Iv, 16);
 42             byte[] btmpMsg = AES_decrypt(Input, Iv, Key);
 43 
 44             int len = BitConverter.ToInt32(btmpMsg, 16);
 45             len = IPAddress.NetworkToHostOrder(len);
 46 
 47 
 48             byte[] bMsg = new byte[len];
 49             byte[] bAppid = new byte[btmpMsg.Length - 20 - len];
 50             Array.Copy(btmpMsg, 20, bMsg, 0, len);
 51             Array.Copy(btmpMsg, 20 + len, bAppid, 0, btmpMsg.Length - 20 - len);
 52             string oriMsg = Encoding.UTF8.GetString(bMsg);
 53             appid = Encoding.UTF8.GetString(bAppid);
 54 
 55 
 56             return oriMsg;
 57         }
 58 
 59         public static String AES_encrypt(String Input, string EncodingAESKey, string appid)
 60         {
 61             byte[] Key;
 62             Key = Convert.FromBase64String(EncodingAESKey + "=");
 63             byte[] Iv = new byte[16];
 64             Array.Copy(Key, Iv, 16);
 65             string Randcode = CreateRandCode(16);
 66             byte[] bRand = Encoding.UTF8.GetBytes(Randcode);
 67             byte[] bAppid = Encoding.UTF8.GetBytes(appid);
 68             byte[] btmpMsg = Encoding.UTF8.GetBytes(Input);
 69             byte[] bMsgLen = BitConverter.GetBytes(HostToNetworkOrder(btmpMsg.Length));
 70             byte[] bMsg = new byte[bRand.Length + bMsgLen.Length + bAppid.Length + btmpMsg.Length];
 71 
 72             Array.Copy(bRand, bMsg, bRand.Length);
 73             Array.Copy(bMsgLen, 0, bMsg, bRand.Length, bMsgLen.Length);
 74             Array.Copy(btmpMsg, 0, bMsg, bRand.Length + bMsgLen.Length, btmpMsg.Length);
 75             Array.Copy(bAppid, 0, bMsg, bRand.Length + bMsgLen.Length + btmpMsg.Length, bAppid.Length);
 76 
 77             return AES_encrypt(bMsg, Iv, Key);
 78 
 79         }
 80         private static string CreateRandCode(int codeLen)
 81         {
 82             string codeSerial = "2,3,4,5,6,7,a,c,d,e,f,h,i,j,k,m,n,p,r,s,t,A,C,D,E,F,G,H,J,K,M,N,P,Q,R,S,U,V,W,X,Y,Z";
 83             if (codeLen == 0)
 84             {
 85                 codeLen = 16;
 86             }
 87             string[] arr = codeSerial.Split(',');
 88             string code = "";
 89             int randValue = -1;
 90             Random rand = new Random(unchecked((int)DateTime.Now.Ticks));
 91             for (int i = 0; i < codeLen; i++)
 92             {
 93                 randValue = rand.Next(0, arr.Length - 1);
 94                 code += arr[randValue];
 95             }
 96             return code;
 97         }
 98 
 99         private static String AES_encrypt(String Input, byte[] Iv, byte[] Key)
100         {
101             var aes = new RijndaelManaged();
102             //秘鑰的大小,以位為單位
103             aes.KeySize = 256;
104             //支持的塊大小
105             aes.BlockSize = 128;
106             //填充模式
107             aes.Padding = PaddingMode.PKCS7;
108             aes.Mode = CipherMode.CBC;
109             aes.Key = Key;
110             aes.IV = Iv;
111             var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
112             byte[] xBuff = null;
113 
114             using (var ms = new MemoryStream())
115             {
116                 using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
117                 {
118                     byte[] xXml = Encoding.UTF8.GetBytes(Input);
119                     cs.Write(xXml, 0, xXml.Length);
120                 }
121                 xBuff = ms.ToArray();
122             }
123             String Output = Convert.ToBase64String(xBuff);
124             return Output;
125         }
126 
127         private static String AES_encrypt(byte[] Input, byte[] Iv, byte[] Key)
128         {
129             var aes = new RijndaelManaged();
130             //秘鑰的大小,以位為單位
131      

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...