C# 版本微信 JS SDK 示例代碼

因爲官方文檔示例代碼裏面沒有包含C#版本的代碼,本文主要分享C#版本的微信JS-SDK簽名處理,因此這裏進行簡單分享。點擊查看源碼地址html

概述

微信JS-SDK是微信公衆平臺面向網頁開發者提供的基於微信內的網頁開發工具包。git

經過使用微信JS-SDK,網頁開發者可藉助微信高效地使用拍照、選圖、語音、位置等手機系統的能力,同時能夠直接使用微信分享、掃一掃、卡券、支付等微信特有的能力,爲微信用戶提供更優質的網頁體驗。github

1. 獲取access token

首先,能夠點擊查看獲取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;
}

2. 獲取jsapi_ticket

生成簽名以前必須先了解一下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;
}

3. noncestr 生成簽名的隨機串

/// <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;
}

4. timestamp生成簽名的時間戳

/// 將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;
}

5. JS-SDK使用權限簽名算法

簽名生成規則以下:參與簽名的字段包括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微信公衆平臺

  • url=http://mp.weixin.qq.com?params=value

步驟1. 對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1:

jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=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 + "&timestamp=" + timestamp + "&url=" + url + "";

string signature = FormsAuthentication.HashPasswordForStoringInConfigFile(rawstring, "SHA1").ToLower();

6. 綜合調用上面的方法並返回參數到須要的頁面

/// 獲得數據包,返回使用頁面 
/// <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 + "&timestamp=" + 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;
}

7. 總結

有問題認真查看文檔或者源碼裏面提Issues。

============================================

圖片描述

相關文章
相關標籤/搜索