微信JS-SDK]微信公衆號JS開發之卡券領取功能詳解

js sdk:javascript

http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.952-.E6.89.80.E6.9C.89JS.E6.8E.A5.E5.8F.A3.E5.88.97.E8.A1.A8php


微信團隊在2015年初改革了微信JS的API,本文主要詳細說明其中用到的卡券領取功能.html


wechat_card_01.jpg

微信卡券須要認證過的公衆號才能申請開通,並且建立的卡券也是要審覈才能投放的.微信的卡券對於用戶體驗上來講比較好,之前促銷活動的優惠券,會經過手機短信等方式發送給用戶,如今有了"微信卡包"這個將卡券集中管理展現的功能,對於商家來講確實是能很好的拉動線下消費.前端


卡券管理入口在微信公衆號管理後臺的功能菜單裏,本文先不提如何建立卡券,主要是講述如何實現將已經生成好的卡券放到本身頁面上讓用戶去領取.java


首先要提到目前公衆號開發中須要記住的3個重要的須要全局緩存的安全加密憑證:web

第一個是:access_token 什麼是access_token呢?看介紹.(轉載請註明出處:猿資猿味)算法

一、爲了保密appsecrect,第三方須要一個access_token獲取和刷新的中控服務器。而其餘業務邏輯服務器所使用的access_token均來自於該中控服務器,不該該各自去刷新,不然會形成access_token覆蓋而影響業務;
二、目前access_token的有效期經過返回的expire_in來傳達,目前是7200秒以內的值。中控服務器須要根據這個有效時間提早去刷新新access_token。在刷新過程當中,中控服務器對外輸出的依然是老access_token,此時公衆平臺後臺會保證在刷新短期內,新老access_token均可用,這保證了第三方業務的平滑過渡;
三、access_token的有效時間可能會在將來有調整,因此中控服務器不只須要內部定時主動刷新,還須要提供被動刷新access_token的接口,這樣便於業務服務器在API調用獲知access_token已超時的狀況下,能夠觸發access_token的刷新流程。

若是第三方不使用中控服務器,而是選擇各個業務邏輯點各自去刷新access_token,那麼就可能會產生衝突,致使服務不穩定。api

接口調用請求說明
數組

http請求方式: GEThttps://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

參數說明緩存

參數 是否必須 說明
grant_type 獲取access_token填寫client_credential
appid 第三方用戶惟一憑證
secret 第三方用戶惟一憑證密鑰,即appsecret

返回說明

正常狀況下,微信會返回下述JSON數據包給公衆號:

{"access_token":"ACCESS_TOKEN","expires_in":7200}
參數 說明
access_token 獲取到的憑證
expires_in 憑證有效時間,單位:秒

 


第二個是:jsapi_ticket 介紹以下.

jsapi_ticket是公衆號用於調用微信JS接口的臨時票據。正常狀況下,jsapi_ticket的有效期爲7200秒,經過access_token來獲取。因爲獲取jsapi_ticket的api調用次數很是有限,頻繁刷新jsapi_ticket會致使api調用受限,影響自身業務,開發者必須在本身的服務全局緩存jsapi_ticket 。

  1. 參考上面介紹獲取access_token(有效期7200秒,開發者必須在本身的服務全局緩存access_token)

  2. 用第一步拿到的access_token 採用http GET方式請求得到jsapi_ticket(有效期7200秒,開發者必須在本身的服務全局緩存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi


成功返回以下JSON:

{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}

得到jsapi_ticket以後,就能夠用來生成JS-SDK權限驗證的簽名了,也須要全局緩存下來。


第三個是:卡券 api_ticket 介紹以下.

卡 券 api_ticket 是用於調用卡券相關接口的臨時票據,有效期爲 7200 秒,經過 access_token 來獲取。這裏要注意與 jsapi_ticket 區分開來。因爲獲取卡券 api_ticket 的 api 調用次數很是有限,頻繁刷新卡券 api_ticket 會致使 api 調用受限,影響自身業務,開發者必須在本身的服務全局緩存卡券 api_ticket 。

  1. 參考上面介紹獲取access_token(有效期7200秒,開發者必須在本身的服務全局緩存access_token)

  2. 用第一步拿到的access_token 採用http GET方式請求得到卡券 api_ticket(有效期7200秒,開發者必須在本身的服務全局緩存卡券 api_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=wx_card


卡券擴展字段cardExt說明

cardExt自己是一個JSON字符串,是商戶爲該張卡券分配的惟一性信息,包含如下字段:

 

字段 是否必填 說明
code 指定的卡券code碼,只能被領一次。use_custom_code字段爲true的卡券必須填寫,非自定義code沒必要填寫。
openid 指定領取者的openid,只有該用戶能領取。bind_openid字段爲true的卡券必須填寫,非自定義openid沒必要填寫。
timestamp 時間戳,商戶生成從1970年1月1日00:00:00至今的秒數,即當前的時間,且最終須要轉換爲字符串形式;

由商戶生成後傳入。

signature 簽名,商戶將接口列表中的參數按照指定方式進行簽名,簽名方式使用SHA1,具體簽名方案參見下文;由商戶按照規範簽名後傳入。
balance 紅包餘額,以分爲單位。紅包類型必填(LUCKY_MONEY),其餘卡券類型不填。

在獲得上面這3個憑證以後就能夠開始接下來的第二步:網站引入微信的JS文件,注入config配置.這一步操做須要注意的是,網站的域名必須在微信公衆號後臺添加到了"設置"->"公衆號設置"->"功能設置"->"JS接口安全域名"裏.

wechat_card_02.jpg

好了,開始引入JS文件.(轉載請註明出處:猿資猿味)

在須要調用JS接口的頁面引入以下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js

備註:支持使用 AMD/CMD 標準模塊加載方法加載


經過config接口注入權限驗證配置

所 有須要使用JS-SDK的頁面必須先注入配置信息,不然將沒法調用(同一個url僅需調用一次,對於變化url的SPA的web app可在每次url變化時進行調用,目前Android微信客戶端不支持pushState的H5新特性,因此使用pushState來實現web app的頁面會致使簽名失敗,此問題會在Android6.2中修復)。

wx.config({
    debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。
    appId: '', // 必填,公衆號的惟一標識
    timestamp: , // 必填,生成簽名的時間戳
    nonceStr: '', // 必填,生成簽名的隨機串
    signature: '',// 必填,簽名,見附錄1
    jsApiList: [] // 必填,須要使用的JS接口列表,全部JS接口列表見附錄2
});

上面的jsApiList內填的是要使用的JS接口,咱們是要讓用戶領取卡券,因此須要用到的JS接口方法:addCard

在html文件中加入如下javascript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
         <script>
                 wx.config({
                     debug:  true ,
                     appId:  "{$signature['appid']}" ,
                     timestamp: {$signature[ 'timestamp' ]},
                     nonceStr:  "{$signature['noncestr']}" ,
                     signature:  "{$signature['signature']}" ,
                     jsApiList: [
                            'addCard'
                            ]
                 });
             wx.ready( function (){
                                 //添加卡券
                 document.querySelector( '#addCard' ).onclick =  function  () {
                     wx.addCard({
                       cardList: [
                         {
                           cardId:  "xxxxxxxxxxxxxxxxxxxxxx" ,
                           cardExt:  '{"timestamp":"1426222398","signature":"fdd892770eb681e925f92acb9015c75107b2227a"}'
                         }
                       ],
                       success:  function  (res) {
                         alert( '已添加卡券:'  + JSON.stringify(res.cardList));
                       }
                     });
                 };
             });
     </script>

上面這段代碼裏重要的參數是:wx.config 這個配置要經過後臺計算好後印射前端html裏面才行,是動態的.簽名算法須要用到的是上面介紹的jsapi_ticket,詳細生成規則算法以下:

參與簽名的字段包括noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其後面部分) 。對全部待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1。這裏 須要注意的是全部參數名均爲小寫字符。對string1做sha1加密,字段名和字段值都採用原始值,不進行URL 轉義。

即signature=sha1(string1)。 

示例:

  • noncestr=Wm3WZYTPz0wzccnW

  • jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg

  • 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

注意事項

  1. 簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。

  2. 簽名用的url必須是調用JS接口頁面的完整URL。

  3. 出於安全考慮,開發者必須在服務器端實現簽名的邏輯。


用php寫一個知足此條件的簽名函數:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function  getJsSign( $jsapi_ticket , $url $timestamp =0,  $noncestr = '' ){
         if  (! $timestamp )
             $timestamp  = time();
         if  (! $noncestr )
             $noncestr  = generateNonceStr();
         $ret  strpos ( $url , '#' );
         if  ( $ret )
             $url  substr ( $url ,0, $ret );
         $url  = trim( $url );
         if  ( empty ( $url ))
             return  false;
         $arrdata  array ( "timestamp"  =>  $timestamp "noncestr"  =>  $noncestr "url"  =>  $url "jsapi_ticket"  =>  $jsapi_ticket );
         ksort( $arrdata );
         $paramstring  "" ;
         foreach ( $arrdata  as  $key  =>  $value ){
             if ( strlen ( $paramstring ) == 0)
                 $paramstring  .=  $key  "="  $value ;
             else
                 $paramstring  .=  "&"  $key  "="  $value ;
         }
         $sign  = sha1( $paramstring );
         if  (! $sign )
             return  false;
         return  $sign ;
}
function  generateNonceStr( $length =16){
     // 密碼字符集,可任意添加你須要的字符
     $chars  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ;
     $str  "" ;
     for ( $i  = 0;  $i  $length $i ++)
     {
     $str  .=  $chars [mt_rand(0,  strlen ( $chars ) - 1)];
     }
     return  $str ;
}

用 generateNonceStr函數生成隨機字符串,再傳入時間戳,當前頁面的url,以及以前緩存好的jsapi_ticket這4個參數通過 getJsSign函數處理便可獲得相應的簽名了,把這些參數映射給js的wx.config,就完成了.這裏的簽名若是不經過是沒辦法調用JS API的,調試前打開debug模式,確保彈出的信息是OK再進行.


JS的簽名經過後,就能夠調試卡券領取接口JS了.方法是addCard  須要注入到wx.ready(function(){})裏面.

1
2
3
4
5
6
7
8
9
10
11
wx.addCard({
     cardList: [
                     {
                 cardId:  "xxxxxxxxxxxxxxxxxxxxxx" ,
                 cardExt:  '{"timestamp":"1426222398","signature":"fdd892770eb681e925f92acb9015c75107b2227a"}'
              }
             ],
     success:  function  (res) {
               alert( '已添加卡券:'  + JSON.stringify(res.cardList));
         }
     });

addCard 方法能夠綁定到監聽事件document.querySelector('#addCard').onclick上.cardId是卡券的ID,生成的時 候可以獲得,也能夠在後臺查看;cardExt的話要注意了,若是生成的卡券沒有用自定義code,那麼只須要timestamp和signature這 兩個字段就好了,可是若是生成的卡券是自定義code的,那麼須要指定一個code給cardExt,不然在領取時按鈕會顯示"參數錯誤".這裏的 signature是卡券的簽名,和上面提到的JS簽名不同的,此簽名的計算方法說明以下:

  1. 將 api_ticket(特別說明:api_ticket 相較 appsecret 安全性更高,同時兼容老版本文檔中使用的 appsecret 做爲簽名憑證。)、timestamp、card_id、code、openid、balance的value值進行字符串的字典序排序。

  2. 將全部參數字符串拼接成一個字符串進行sha1加密,獲得signature。

  3. signature中的timestamp和card_ext中的timestamp必須保持一致。

  4. 假 如數據示例中code=23456,timestamp=141231233,card_id=345667,api_ticket=45678則 signature=sha1(14123123323456345667456789)=4F76593A4245644FAE4E1BC940F6422A0C3EC03E。

卡券簽名cardSign說明

  1. 將 api_ticket(特別說明:api_ticket 相較 appsecret 安全性更高,同時兼容老版本文檔中使用的 appsecret 做爲簽名憑證。)、app_id、location_id、times_tamp、nonce_str、card_id、card_type的value 值進行字符串的字典序排序。

  2. 將全部參數字符串拼接成一個字符串進行sha1加密,獲得cardSign。


用php寫一個知足此條件的簽名函數:

1
2
3
4
5
6
7
function  getCardSign( $card ){
         sort( $card ,SORT_STRING);
         $sign  = sha1(implode( $card ));
         if  (! $sign )
             return  false;
         return  $sign ;
}

$card是一個數組,裏面必須包含時間戳,卡券 api_ticket,若是是自定義的code或者指定openid的用戶才能領取,須要把這些額外參數也傳到$card中,通過字典排序sha1加密後就能獲得卡券簽名了.

轉載自:https://www.cnblogs.com/ldms/p/5241756.html

相關文章
相關標籤/搜索