此文將分兩篇講解,主要分爲如下幾步服務器
其實圖靈機器人搭載微信公衆號很簡單,只須要把圖靈的地址配到公衆後臺就能夠了。
不過這樣作以後也就沒有任何擴展的可能了,所以本身實現一套!微信
在開發者首次提交驗證申請時,微信服務器將發送GET請求到填寫的URL上,而且帶上四個參數(signature、timestamp、nonce、echostr),開發者經過對簽名(即signature)的效驗,來判斷此條消息的真實性。微信開發
此後,每次開發者接收用戶消息的時候,微信也都會帶上前面三個參數(signature、timestamp、nonce)訪問開發者設置的URL,開發者依然經過對簽名的效驗判斷此條消息的真實性。效驗方式與首次提交驗證申請一致。ide
根據微信開發者平臺中的描述,咱們在首次提交驗證申請及接收用戶消息時,都須要校驗簽名以確保消息來源真實。加密
參與簽名的參數爲timestamp
、nonce
及token
(即開發者中心中配置的Token令牌)spa
加密/校驗流程以下:code
因爲這個東西在接收消息時是通用的,咱們可使用受權過濾器AuthorizeAttribute
來實現。視頻
using System.Configuration; using System.Net; using System.Net.Http; using System.Web; using System.Web.Http; using System.Linq; using System.Web.Http.Controllers; using Efh.Core.Security; namespace Efh.Blog.Web.Areas.WeiXin.Filter { public class WXAuthorizeAttribute : AuthorizeAttribute { /// <summary> /// 簽名Key /// </summary> private string _wxToken = ConfigurationManager.AppSettings["WXToken"]; /// <summary> /// 是否經過受權 /// </summary> /// <param name="actionContext">上下文</param> /// <returns>是否成功</returns> protected override bool IsAuthorized(HttpActionContext actionContext) { var requestQueryPairs = actionContext.Request.GetQueryNameValuePairs().ToDictionary(k => k.Key, v => v.Value); if (requestQueryPairs.Count == 0 || !requestQueryPairs.ContainsKey("timestamp") || !requestQueryPairs.ContainsKey("signature") || !requestQueryPairs.ContainsKey("nonce")) { return false; } string[] waitEncryptParamsArray = new[] { _wxToken, requestQueryPairs["timestamp"], requestQueryPairs["nonce"] }; string waitEncryptParamStr = string.Join("", waitEncryptParamsArray.OrderBy(m => m)); string encryptStr = HashAlgorithm.SHA1(waitEncryptParamStr); return encryptStr.ToLower().Equals(requestQueryPairs["signature"].ToLower()); } /// <summary> /// 處理未受權請求 /// </summary> /// <param name="actionContext">上下文</param> protected sealed override void HandleUnauthorizedRequest(HttpActionContext actionContext) { actionContext.Response = actionContext.Request.CreateResponse( HttpStatusCode.Unauthorized, new { status = "sign_error" }); } } }
將該特性聲明在咱們的微信Controller或者Action上,咱們的簽名校驗便完成了。xml
首次提交驗證申請,微信服務器來調的時候是Get請求,並且要求咱們將echostr原樣返回。
注意,是原樣返回。不是XML,也不是Json,<string>echostr</string>
和"echostr"都是不行的!排序
囊中羞澀,本人使用的是虛擬主機搭載在原有的項目中,故新建微信區域(WeiXin)來實現。WeiXinAreaRegistration.cs文件以下:
public class WeiXinAreaRegistration : AreaRegistration { public override string AreaName { get { return "WeiXin"; } } public override void RegisterArea(AreaRegistrationContext context) { context.Routes.MapHttpRoute( "WeiXinProcessor", "WeiXin/{controller}", new { controller = "Processor" } ); } }
新建Processor控制器,實現以下:
[WXAuthorize] public class ProcessorController : ApiController { public HttpResponseMessage Get() { var requestQueryPairs = Request.GetQueryNameValuePairs().ToDictionary(k => k.Key, v => v.Value); return new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(requestQueryPairs["echostr"]), }; } }
上述咱們便實現了首次微信的驗證。
微信將請求的消息分爲六種:文本消息、圖片消息、語音消息、視頻消息、地理位置消息、連接消息,其實咱們還能夠將事件推送也理解爲其中一種。
將響應的消息分爲六種:
1. 回覆文本消息
2. 回覆圖片消息
3. 回覆語音消息
4. 回覆視頻消息
5. 回覆音樂消息
6. 回覆圖文消息
。咱們在這兒主要使用文本消息和圖文消息。
分析後咱們發現,ToUserName
、FromUserName
、CreateTime
、MsgType
是全部消息共有的參數。同時也是咱們響應時必需的參數。
咱們建立消息基類和消息類型枚舉以下
public class BaseMsg { public string ToUserName { get; set; } public string FromUserName { get; set; } public long CreateTime { get; set; } public MsgType MsgType { get; set; } } public enum MsgType { [XmlEnum("event")] Event, [XmlEnum("text")] Text, [XmlEnum("image")] Image, [XmlEnum("voice")] Voice, [XmlEnum("video")] Video, [XmlEnum("music")] Music, [XmlEnum("news")] News }
此處枚舉字段標註的XmlEnum稍候解釋。
然後按照各消息類型的非共有的參數,分別建立對應消息的實體類
文本消息:
[XmlRoot("xml")] public class TextMsg : BaseMsg { public string Content { get; set; } }
圖文消息:
[XmlRoot("xml")] public class NewsMsg : BaseMsg { public int ArticleCount { get; set; } [XmlArray("Articles")] [XmlArrayItem("item")] public List<NewsInfo> Articles { get; set; } } public class NewsInfo { public string Title { get; set; } public string Description { get; set; } public string PicUrl { get; set; } public string Url { get; set; } }
等等。
剛纔下班,朋友喊了,勿勿忙忙就提交了。。。如今繼續!
接下來咱們就能夠開始接收微信的消息了
微信是經過Post,從正文中以XML的格式將參數傳遞過來的
var requestContent = Request.Content.ReadAsStreamAsync().Result;
將正文參數讀取出來後,轉爲Xml
XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(requestContent);
這樣,咱們即可以讀取到咱們須要的內容了
string msgTypeStr = xmlDoc.SelectSingleNode("xml/MsgType").InnerText;//消息類型 string userName = xmlDoc.SelectSingleNode("xml/FromUserName").InnerText;//來源用戶標識 string efhName = xmlDoc.SelectSingleNode("xml/ToUserName").InnerText;//咱們的用戶標識
然後,咱們根據消息類型,進行進一步的處理。
靜候片刻,第二篇立刻奉上...