using System; using System.Threading.Tasks; using System.Collections.Generic; using Newtonsoft.Json; using WXERP.Models; namespace WXERP.Services { /// <summary> /// 系統消息上下文 /// </summary> public class MessageContext { /// <summary> /// 獲取AccessToken的全局鎖 /// </summary> private readonly static object SyncLock = new object(); private static Dictionary<string, AccessTokenResponseModel> tokenCache = new Dictionary<string, AccessTokenResponseModel>(); /// <summary> /// 發送訂閲消息 /// </summary> /// <param>消息内容</param> /// <param>可能由於獲取的token錯誤</param> /// <returns></returns> public static bool SendSubscribeMsg(SubscribeMessageModel msg, out string errMsg) { errMsg = ""; try { string token = GetAccessToken(); if (token.Length < 20) { errMsg = "Failed to send subscription message, Access token error!"; return false; } string url = string.Format(Common.Configuration["WX:MessageSendUrl"], token); string requestJson = JsonConvert.SerializeObject(msg); string responseJson = HttpHelper.HttpPost(url, requestJson, "application/json", null); var msgResponse = JsonConvert.DeserializeObject<SubscribeMsgResponseModel>(responseJson); if (msgResponse.Errcode != 0) { errMsg = string.Format("Failed to send subscription message, {0}", msgResponse.Errmsg); return false; } } catch (Exception exp) { throw new Exception("SendSubscribeMsg: " + exp.Message); } return true; } /// <summary> /// 獲取小程序訪問token /// </summary> /// <returns></returns> private static string GetAccessToken() { lock (SyncLock) { string appid = Common.Configuration["WX:AppId"]; string appsecret = Common.Configuration["WX:AppSecret"]; string accessTokenUrl = string.Format(Common.Configuration["WX:AccessTokenUrl"], appid, appsecret); AccessTokenResponseModel result = null; if (tokenCache.ContainsKey(appid)) result = tokenCache[appid]; if (result == null) { string responseJson = HttpHelper.HttpGet(accessTokenUrl, null); result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson); result.Create_time = DateTime.Now; tokenCache.Add(appid, result); } else if (DateTime.Compare(result.Create_time.AddSeconds(result.Expires_id), DateTime.Now) < 1) { string responseJson = HttpHelper.HttpGet(accessTokenUrl, null); result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson); result.Create_time = DateTime.Now; tokenCache[appid] = result; } return result.Access_token; } } /// <summary> /// 驗證消息來自於微信服務器 /// </summary> /// <param>微信加密簽名,signature結合了開發者填寫的token、timestamp、nonce</param> /// <param>時間戳</param> /// <param>隨機數</param> /// <returns></returns> public async Task<bool> CheckSignature(string signature, string timestamp, string nonce) { string token = Common.Configuration["WX:SignatureToken"]; string[] tmpArr = { token, timestamp, nonce }; Array.Sort(tmpArr); string tmpStr = string.Join("", tmpArr); tmpStr = Common.SHA1(tmpStr); if (!tmpStr.Equals(signature, StringComparison.OrdinalIgnoreCase)) return false; await Task.CompletedTask; return true; } } }
八、编写消息推送配置签名认证控制器