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


js sdk:

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.A8


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


wechat_card_01.jpg

微信卡券需要認證過的公眾號才能申請開通,而且創建的卡券也是要審核才能投放的.微信的卡券對於用戶體驗上來說比較好,以前促銷活動的優惠券,會通過手機短信等方式發送給用戶,現在有了"微信卡包"這個將卡券集中管理展示的功能,對於商家來說確實是能很好的拉動線下消費.


卡券管理入口在微信公眾號管理后台的功能菜單里,本文先不提如何創建卡券,主要是講述如何實現將已經生成好的卡券放到自己頁面上讓用戶去領取.


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

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

1、為了保密appsecrect,第三方需要一個access_token獲取和刷新的中控服務器。而其他業務邏輯服務器所使用的access_token均來自於該中控服務器,不應該各自去刷新,否則會造成access_token覆蓋而影響業務;
2、目前access_token的有效期通過返回的expire_in來傳達,目前是7200秒之內的值。中控服務器需要根據這個有效時間提前去刷新新access_token。在刷新過程中,中控服務器對外輸出的依然是老access_token,此時公眾平台后台會保證在刷新短時間內,新老access_token都可用,這保證了第三方業務的平滑過渡;
3、access_token的有效時間可能會在未來有調整,所以中控服務器不僅需要內部定時主動刷新,還需要提供被動刷新access_token的接口,這樣便於業務服務器在API調用獲知access_token已超時的情況下,可以觸發access_token的刷新流程。

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

接口調用請求說明

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM