因爲官方文檔示例代碼裏面沒有包含C#版本的代碼,本文主要分享C#版本的微信JS-SDK簽名處理,因此這裏進行簡單分享。點擊查看源碼地址。html
微信JS-SDK是微信公衆平臺面向網頁開發者提供的基於微信內的網頁開發工具包。git
經過使用微信JS-SDK,網頁開發者可藉助微信高效地使用拍照、選圖、語音、位置等手機系統的能力,同時能夠直接使用微信分享、掃一掃、卡券、支付等微信特有的能力,爲微信用戶提供更優質的網頁體驗。github
首先,能夠點擊查看獲取token的官方描述。access_token的有效期目前爲2個小時,需定時刷新,重複獲取將致使上次獲取的access_token失效。因爲接口頻率限制,開發者必須在本身的服務全局緩存jsapi_ticket。算法
/// <summary> /// 獲取AccessToken_token /// </summary> /// <returns></returns> public static AccessToken Getaccess() { string Str = GetJson(string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", wxAppId, wxAppSecret)); AccessToken m = JsonHelper.ParseFromJson<AccessToken>(Str); return m; } /// 獲取token,若是存在且沒過時,則直接取token /// <summary> /// 獲取token,若是存在且沒過時,則直接取token /// </summary> /// <returns></returns> public static string GetExistAccessToken() { // 讀取XML文件中的數據 string filepath = System.Web.HttpContext.Current.Server.MapPath("/XMLToken.xml"); FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); StreamReader str = new StreamReader(fs, System.Text.Encoding.UTF8); XmlDocument xml = new XmlDocument(); xml.Load(str); str.Close(); str.Dispose(); fs.Close(); fs.Dispose(); string Token = xml.SelectSingleNode("xml").SelectSingleNode("AccessToken").InnerText; DateTime AccessTokenExpires = Convert.ToDateTime(xml.SelectSingleNode("xml").SelectSingleNode("AccessExpires").InnerText); //若是token過時,則從新獲取token if (DateTime.Now >= AccessTokenExpires) { AccessToken mode = Getaccess(); //將token存到xml文件中,全局緩存 xml.SelectSingleNode("xml").SelectSingleNode("AccessToken").InnerText = mode.access_token; DateTime _AccessTokenExpires = DateTime.Now.AddSeconds(mode.expires_in); xml.SelectSingleNode("xml").SelectSingleNode("AccessExpires").InnerText = _AccessTokenExpires.ToString(); xml.Save(filepath); Token = mode.access_token; } return Token; }
生成簽名以前必須先了解一下jsapi_ticket,jsapi_ticket是公衆號用於調用微信JS接口的臨時票據。正常狀況下,jsapi_ticket的有效期爲7200秒,經過access_token來獲取。因爲獲取jsapi_ticket的api調用次數很是有限,頻繁刷新jsapi_ticket會致使api調用受限,影響自身業務,開發者必須在本身的服務全局緩存jsapi_ticket 。c#
/// 獲取jsapi_ticket /// <summary> /// 獲取jsapi_ticket /// </summary> /// <param name="access"></param> /// <returns></returns> private static JSTicket getJSTicketTicket(string access) { string Str = GetJson("https://api.weixin.qq.com/cgi-bin/ticket/getticket?AccessToken_token=" + access + "&type=JSTicket"); JSTicket jt = JsonConvert.DeserializeObject<JSTicket>(Str); return jt; } /// <summary> /// 獲取jsapi_ticket,若是存在且沒過時,則直接取jsapi_ticket /// </summary> /// <returns></returns> public static string GetExistJSTicket() { // 讀取XML文件中的數據 string filepath = System.Web.HttpContext.Current.Server.MapPath("/XMLToken.xml"); FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); StreamReader str = new StreamReader(fs, System.Text.Encoding.UTF8); XmlDocument xml = new XmlDocument(); xml.Load(str); str.Close(); str.Dispose(); fs.Close(); fs.Dispose(); string ticket = xml.SelectSingleNode("xml").SelectSingleNode("JSTicket").InnerText; DateTime AccessTokenExpires = Convert.ToDateTime(xml.SelectSingleNode("xml").SelectSingleNode("JSAccessExpires").InnerText); //若是jsapi_ticket過時,則從新獲取token if (DateTime.Now >= AccessTokenExpires) { string Token = xml.SelectSingleNode("xml").SelectSingleNode("AccessToken").InnerText; JSTicket mode = getJSTicketTicket(Token); if (mode.ticket != null && mode.expires_in != null) { //將jsapi_ticket存到xml文件中,全局緩存 xml.SelectSingleNode("xml").SelectSingleNode("JSTicket").InnerText = mode.ticket; DateTime _AccessTokenExpires = DateTime.Now.AddSeconds(int.Parse(mode.expires_in)); xml.SelectSingleNode("xml").SelectSingleNode("JSAccessExpires").InnerText = _AccessTokenExpires.ToString(); xml.Save(filepath); ticket = mode.ticket; } else { ticket = ""; } } return ticket; }
/// <summary> /// 建立隨機字符串 /// </summary> /// <returns></returns> private static string createNonceStr() { int length = 16; string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; string str = ""; Random rad = new Random(); for (int i = 0; i < length; i++) { str += chars.Substring(rad.Next(0, chars.Length - 1), 1); } return str; }
/// 將c# DateTime時間格式轉換爲Unix時間戳格式 /// <summary> /// 將c# DateTime時間格式轉換爲Unix時間戳格式 /// </summary> /// <param name="time">時間</param> /// <returns>double</returns> public static int ConvertDateTimeInt(System.DateTime time) { int intResult = 0; System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); intResult = Convert.ToInt32((time - startTime).TotalSeconds); return intResult; }
簽名生成規則以下:參與簽名的字段包括noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其後面部分) 。對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1。這裏須要注意的是全部參數名均爲小寫字符。對string1做sha1加密,字段名和字段值都採用原始值,不進行URL 轉義。api
即 signature=sha1(string1)
。 示例:緩存
noncestr=Wm3WZYTPz0wzccnW微信
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qgapp
timestamp=1414587457微信公衆平臺
步驟1. 對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
步驟2. 對string1進行sha1簽名,獲得signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意:生成簽名的url參數不能包含中文字符,中文字符須要單獨轉義。不過源碼中已經用HttpContext.Current.Request.Url.AbsoluteUri進行處理。
下面是生成簽名的代碼:
// 這裏參數的順序要按照 key 值 ASCII 碼升序排序 string rawstring = "JSTicket_ticket=" + JSTicketTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url + ""; string signature = FormsAuthentication.HashPasswordForStoringInConfigFile(rawstring, "SHA1").ToLower();
/// 獲得數據包,返回使用頁面 /// <summary> /// 獲得數據包,返回使用頁面 /// </summary> /// <returns></returns> public static Hashtable getSignPackage() { //AccessToken ace = Getaccess(); string token = GetExistAccessToken(); string JSTicketTicket = GetExistJSTicket(); string url = HttpContext.Current.Request.Url.AbsoluteUri; string timestamp = Convert.ToString(ConvertDateTimeInt(DateTime.Now)); string nonceStr = createNonceStr(); // 這裏參數的順序要按照 key 值 ASCII 碼升序排序 string rawstring = "JSTicket_ticket=" + JSTicketTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url + ""; string signature = FormsAuthentication.HashPasswordForStoringInConfigFile(rawstring, "SHA1").ToLower(); //string signature = SHA1_Hash(rawstring); Hashtable signPackage = new Hashtable(); signPackage.Add("appId", wxAppId); signPackage.Add("nonceStr", nonceStr); signPackage.Add("timestamp", timestamp); signPackage.Add("url", url); signPackage.Add("signature", signature); signPackage.Add("rawString", rawstring); signPackage.Add("JSTicketTicket", JSTicketTicket); return signPackage; }
有問題認真查看文檔或者源碼裏面提Issues。
============================================