小程序卡券簽名錯誤的解決方案

這個問題我相信很多人都碰到過窿克,我也不另外。遇到這個問題的時候毛甲,也上網搜索過年叮,可惜,網上的答案都是千篇一律丽啡,沒辦法我只能仔細研究官方文檔谋右。最終,讓我搞定了這個問題补箍。各位網友改执,只要你按照我的步驟走下去,100%包你過坑雅。我們先看一張效果圖:


效果圖

下面我先從后端為大家講解辈挂,原理我就不說了,大家自己看官網裹粤。由于我的后端用的是PHP终蒂,因此使用的是thinkphp5來實現(xiàn)這個功能,不懂thinkphp5的朋友可以去網上惡補一下,后期我會單獨推出hinkphp5開發(fā)視頻拇泣,我會盡最大努力能讓大家看懂噪叙。在這里需要重點說明一下,一定要把小程序與微信公眾號綁定在一起霉翔。這個可以通過微信公眾號內“綁定小程序”功能來實現(xiàn)睁蕾。

一、獲取access_token
public function getAccessToken() {
$appId = '微信公眾號的APPID'; //注意债朵,這里不是微信小程序的APPID
$secret = '微信公眾號的secret'; //注意子眶,這里也不是微信小程序的secret
/*以上兩個參數,是在微信公眾號的基本配置里面查看
注意:這個accesstoken一定要緩存起來序芦,因為它有時效性(7200秒)
*/
 $access_token = Catch::get('access_token');
        if ($access_token) {
            return $access_token;
        } else {
            $timeout = 5;
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appId."&secret=" . secret;
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl,CURLOPT_URL,$url);
            curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
            curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
            //獲取access_token和openid,轉換為數組
            $access = json_decode(curl_exec($curl),true);
            Cache::set('access_token', $access['access_token'], 7200);
            return $access['access_token'];
        }
}
二臭杰、獲取卡券的ticket
/**
     * 獲取卡券ticket
     * @return mixed|string
     */
    public function getCardApiTicket() {
        $api_ticket = Cache::get('card_api_ticket');
        if ($api_ticket) {
           return $api_ticket;
        } else {
            $token = $this->getAccess_token(); //上一步得到的access_token
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" . $token . "&type=wx_card";
            $api_ticket = $this->request_Get($url);
            $res = json_decode($api_ticket, true);
            Cache::get('card_api_ticket',$res['ticket'],7200);
            return $res['ticket'];
        }
    }
 
/***
 * GET方法
 * @param $url
 * @return mixed
 */
public function request_Get($url){
    $curl = curl_init();
    $timeout = 5;
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl,CURLOPT_URL,$url);
    curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
    $tmpInfo = curl_exec($curl);     //返回api的json對象
    //關閉URL請求
    curl_close($curl);
    return $tmpInfo;    //返回json對象
}
三、卡券簽名

這一步是非常關鍵的一步谚中,很多人都是在這里栽跟頭的渴杆。為了不讓大家走彎路,我會詳細說明藏杖。根據官網的要求将塑,我們添加卡券的時候需要提供卡券ID,時間戳蝌麸,簽名点寥,這里最難的一個就是簽名,根據我本人的多次調試来吩,終于找到了一勞永逸的方法敢辩。代碼如下:

/**
     * 獲取卡券簽名
     * @param $timestamp int 時間戳
     * @param $api_ticket string 卡券ticket
     * @param $noncestr string 隨機字符串,由開發(fā)者設置傳入弟疆,加強安全性(若不填寫可能被重放請求)戚长。隨機字符串,不長于 32 位
     * @param $card_id string 卡券ID
     * @param $openid string 用戶的微信小程序openid
     * @param $code string 卡的編號
     * @return array
     */
    public function cardSignature($timestamp, $api_ticket, $noncestr, $card_id, $openid, $code){
        $arr = array();
        $arr['timestamp'] = $timestamp;
        $arr['code'] = $code;
        $arr['nonce_str'] = $noncestr;
        $arr['ticket'] = $api_ticket;
        $arr['openid'] = $openid;
        $arr['card_id'] = $card_id;
//根據官網說明怠苔,卡券簽名需要的參數有:timestamp(時間戳),code(卡的編號)同廉,nonce_str(隨機字符串),ticket(卡券ticket)柑司,openid(用戶的openid)迫肖,card_id(卡券的ID)
        sort($arr, SORT_STRING); //排序,這一步一定要有攒驰,否則會不成功
        $str = '';
        foreach ($arr as $v) {
            $str .= $v;
        }
//通過foreach組裝成字符串
        $signature = sha1($str); //最后通過sha1生成簽名
        return array('code' => $code,'openid' =>$openid,'timestamp'=>$timestamp,'nonce_str'=>$noncestr,'signature'=>$signature);
    }
四蟆湖、獲取卡券
/**
     * 獲取用戶卡券
     * @return mixed
     */
    public function getUserCard() {
        $openid = input('openid'); //前端傳的參數
      
        $token = $this->getAccess_token(); //這里就是之前獲取的access_token
        $url = "https://api.weixin.qq.com/card/user/getcardlist?access_token=" . $token; //調用接口憑證
        $data = array();
        $data['openid'] = $openid;
        $dataRes = $this->request_post($url, json_encode($data));
        $res = json_decode($dataRes,true);
       
        if ($res['errcode'] == 0) {
            //成功
            $list = array();
            $timestamp = time(); //時間戳
            $card_ticket = $this->getCardApiTicket(); //獲取卡券API_ticket
            $nonce_str = $this->generateNonceStr(); //隨機字符串
            foreach ($res['card_list'] as $k => $val) {
                $result = $this->cardSignature($timestamp,$card_ticket,$nonce_str,$val['card_id'],$openid,$val['code']);
                $list['cardId'] = $val['card_id'];
                $list['cardExt'] = json_encode($result);
            }
            return $this->resMap(200, $list, $list);
        } else {
            return $this->resMap(4002,'暫時沒有數據','暫時沒有數據');
        }
    }
 
/**
 * 發(fā)送post請求
 * @param string $url
 * @param string $param
 * @return bool|mixed
 */
public function request_post($url = '', $param = '')
{
    if (empty($url) || empty($param)) {
        return false;
    }
    $postUrl = $url;
    $curlPost = $param;
    $ch = curl_init(); //初始化curl
    curl_setopt($ch, CURLOPT_URL, $postUrl); //抓取指定網頁
    curl_setopt($ch, CURLOPT_HEADER, 0); //設置header
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求結果為字符串且輸出到屏幕上
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_POST, 1); //post提交方式
    curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
    $data = curl_exec($ch); //運行curl
    curl_close($ch);
    return $data;
}
 
/**
 * 密碼字符集
 * @param int $length
 * @return string
 */
public function generateNonceStr($length=16){
    // 密碼字符集,可任意添加你需要的字符
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $str = "";
    for($i = 0; $i < $length; $i++)
    {
        $str .= $chars[mt_rand(0, strlen($chars) - 1)];
    }
    return $str;
}
 
  /**
     * 返回提示信息
     * @param $code string 錯誤碼  4001 空值  4002 格式不正確  4003 長度  4004 提示  200正確放回 ,0失敗
     * @param $msg string 錯誤描述
     * @param $data string 返回值
     * @return array
     */
    public function resMap($code, $msg, $data)
    {
        $map = array();
        $map['errMsg'] = $msg;
        $map['data'] = $data;
        $map['errCode'] = $code;
        return json($map);
    }

以上就是后端的核心代碼玻粪,下面我們把上面的代碼重新整理在一個頁面上隅津。

namespace app\rest\controller;
 
use think\Controller;
use think\Cache;
use think\Log;
 
//類名為Card
class Card extends Controller {
 
/**
獲取access_token
*/
 public function getAccessToken() {
$appId = '微信公眾號的APPID'; //注意诬垂,這里不是微信小程序的APPID
$secret = '微信公眾號的secret'; //注意,這里也不是微信小程序的secret
/*以上兩個參數伦仍,是在微信公眾號的基本配置里面查看
注意:這個accesstoken一定要緩存起來结窘,因為它有時效性(7200秒)
*/
 $access_token = Catch::get('access_token');
        if ($access_token) {
            return $access_token;
        } else {
            $timeout = 5;
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appId."&secret=" . secret;
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl,CURLOPT_URL,$url);
            curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
            curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
            //獲取access_token和openid,轉換為數組
            $access = json_decode(curl_exec($curl),true);
            Cache::set('access_token', $access['access_token'], 7200);
            return $access['access_token'];
        }
  }
 
/**
     * 獲取卡券ticket
     * @return mixed|string
     */
    public function getCardApiTicket() {
        $api_ticket = Cache::get('card_api_ticket');
        if ($api_ticket) {
           return $api_ticket;
        } else {
            $token = $this->getAccess_token(); //上一步得到的access_token
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" . $token . "&type=wx_card";
            $api_ticket = $this->request_Get($url);
            $res = json_decode($api_ticket, true);
            Cache::get('card_api_ticket',$res['ticket'],7200);
            return $res['ticket'];
        }
    }
 
/***
 * GET方法
 * @param $url
 * @return mixed
 */
public function request_Get($url){
    $curl = curl_init();
    $timeout = 5;
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl,CURLOPT_URL,$url);
    curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
    $tmpInfo = curl_exec($curl);     //返回api的json對象
    //關閉URL請求
    curl_close($curl);
    return $tmpInfo;    //返回json對象
}
 
 /**
     * 獲取卡券簽名
     * @param $timestamp int 時間戳
     * @param $api_ticket string 卡券ticket
     * @param $noncestr string 隨機字符串,由開發(fā)者設置傳入充蓝,加強安全性(若不填寫可能被重放請求)晦鞋。隨機字符串,不長于 32 位
     * @param $card_id string 卡券ID
     * @param $openid string 用戶的微信小程序openid
     * @param $code string 卡的編號
     * @return array
     */
    public function cardSignature($timestamp, $api_ticket, $noncestr, $card_id, $openid, $code){
        $arr = array();
        $arr['timestamp'] = $timestamp;
        $arr['code'] = $code;
        $arr['nonce_str'] = $noncestr;
        $arr['ticket'] = $api_ticket;
        $arr['openid'] = $openid;
        $arr['card_id'] = $card_id;
//根據官網說明棺克,卡券簽名需要的參數有:timestamp(時間戳),code(卡的編號),nonce_str(隨機字符串)线定,ticket(卡券ticket)娜谊,openid(用戶的openid),card_id(卡券的ID)
        sort($arr, SORT_STRING); //排序斤讥,這一步一定要有纱皆,否則會不成功
        $str = '';
        foreach ($arr as $v) {
            $str .= $v;
        }
//通過foreach組裝成字符串
        $signature = sha1($str); //最后通過sha1生成簽名
        return array('code' => $code,'openid' =>$openid,'timestamp'=>$timestamp,'nonce_str'=>$noncestr,'signature'=>$signature);
    }
 /**
     * 獲取用戶卡券
     * @return mixed
     */
    public function getUserCard() {
        $openid = input('openid'); //前端傳的參數
       
      
        $token = $this->getAccess_token(); //這里就是之前獲取的access_token
        $url = "https://api.weixin.qq.com/card/user/getcardlist?access_token=" . $token; //調用接口憑證
        $data = array();
        $data['openid'] = $openid;
        $dataRes = $this->request_post($url, json_encode($data));
        $res = json_decode($dataRes,true);
       
        if ($res['errcode'] == 0) {
            //成功
            $list = array();
            $timestamp = time(); //時間戳
            $card_ticket = $this->getCardApiTicket(); //獲取卡券API_ticket
            $nonce_str = $this->generateNonceStr(); //隨機字符串
            foreach ($res['card_list'] as $k => $val) {
                $result = $this->cardSignature($timestamp,$card_ticket,$nonce_str,$val['card_id'],$openid,$val['code']);
                $list['cardId'] = $val['card_id'];
                $list['cardExt'] = json_encode($result);
            }
            return $this->resMap(200, $list, $list);
        } else {
            return $this->resMap(4002,'暫時沒有數據','暫時沒有數據');
        }
    }
 
/**
 * 發(fā)送post請求
 * @param string $url
 * @param string $param
 * @return bool|mixed
 */
public function request_post($url = '', $param = '')
{
    if (empty($url) || empty($param)) {
        return false;
    }
    $postUrl = $url;
    $curlPost = $param;
    $ch = curl_init(); //初始化curl
    curl_setopt($ch, CURLOPT_URL, $postUrl); //抓取指定網頁
    curl_setopt($ch, CURLOPT_HEADER, 0); //設置header
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求結果為字符串且輸出到屏幕上
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_POST, 1); //post提交方式
    curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
    $data = curl_exec($ch); //運行curl
    curl_close($ch);
    return $data;
}
 
/**
 * 密碼字符集
 * @param int $length
 * @return string
 */
public function generateNonceStr($length=16){
    // 密碼字符集,可任意添加你需要的字符
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $str = "";
    for($i = 0; $i < $length; $i++)
    {
        $str .= $chars[mt_rand(0, strlen($chars) - 1)];
    }
    return $str;
}
 
  /**
     * 返回提示信息
     * @param $code string 錯誤碼  4001 空值  4002 格式不正確  4003 長度  4004 提示  200正確放回 ,0失敗
     * @param $msg string 錯誤描述
     * @param $data string 返回值
     * @return array
     */
    public function resMap($code, $msg, $data)
    {
        $map = array();
        $map['errMsg'] = $msg;
        $map['data'] = $data;
        $map['errCode'] = $code;
        return json($map);
    }
 
}

前端如何使用

一芭商、獲取用戶的openid

這里我們可以通過wx.login()方法獲取,參考地址:https://developers.weixin.qq.com/miniprogram/dev/api/api-login.html派草,然后把openid作為一個參數傳遞給后端。在這里我插一句铛楣,要想獲取用戶的openid近迁,我們需要通過wx.login方法往后退傳遞code參數,通過這個參數我們才能獲取openid簸州,如何操作鉴竭,我們會在下一章節(jié)詳細講解。包括建表岸浑、后端搏存、前端等知識。

這里假設我們已經有了openid,那么我們就通過這個openid獲取卡券矢洲,我把代碼寫在index.js里面璧眠,具體位置為onload:function();代碼如下:

 /**
   * 生命周期函數--監(jiān)聽頁面加載
   */
  onLoad: function (options) {
   let that = this;
    let openid = userInfo.m_openid;
wx.request({
  url: 'https://xxx.com/rest/Card/getUserCard', //僅為示例,并非真實的接口地址
method: 'POST', //POST一定要大寫
  data: {
     openid: openid,
  },
  header: {
    'content-type': 'application/json' // 默認值
  },
  success: function(res) {
   if (res.errCode == 200) {
//wx.addCard也就是微信小程序的API读虏,地址:https://developers.weixin.qq.com/miniprogram/dev/api/card.html#wxaddcardobject
        wx.addCard({
          cardList: [res.errMsg],
          success: function(rs) {
            console.log(rs) // 卡券添加結果
          }
        })
      }  else {
// wx.showModal 彈窗
        wx.showModal({
          title: '提示',
          content: res.errMsg,
          showCancel: false,
          success: function(res) {
console.log(res);
          }
        })
      }
  }
})
   
  },

以上就是解決簽名錯誤的詳細方案责静,希望對大家有用,謝謝掘譬!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末泰演,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子葱轩,更是在濱河造成了極大的恐慌睦焕,老刑警劉巖藐握,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異垃喊,居然都是意外死亡猾普,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門本谜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來初家,“玉大人,你說我怎么就攤上這事乌助×镌冢” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵他托,是天一觀的道長掖肋。 經常有香客問我,道長赏参,這世上最難降的妖魔是什么志笼? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮把篓,結果婚禮上纫溃,老公的妹妹穿的比我還像新娘。我一直安慰自己韧掩,他們只是感情好紊浩,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疗锐,像睡著了一般郎楼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窒悔,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天呜袁,我揣著相機與錄音,去河邊找鬼简珠。 笑死阶界,一個胖子當著我的面吹牛,可吹牛的內容都是我干的聋庵。 我是一名探鬼主播膘融,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼祭玉!你這毒婦竟也來了氧映?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤脱货,失蹤者是張志新(化名)和其女友劉穎岛都,沒想到半個月后律姨,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡臼疫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年择份,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烫堤。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡荣赶,死狀恐怖,靈堂內的尸體忽然破棺而出鸽斟,到底是詐尸還是另有隱情拔创,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布富蓄,位于F島的核電站伏蚊,受9級特大地震影響,放射性物質發(fā)生泄漏格粪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一氛改、第九天 我趴在偏房一處隱蔽的房頂上張望帐萎。 院中可真熱鬧,春花似錦胜卤、人聲如沸疆导。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澈段。三九已至,卻和暖如春舰攒,著一層夾襖步出監(jiān)牢的瞬間败富,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工摩窃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留兽叮,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓猾愿,卻偏偏與公主長得像鹦聪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蒂秘,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內容

  • 轉載鏈接 注:本文轉載知乎上的回答 作者:初雪 鏈接:https://www.zhihu.com/question...
    pengshuangta閱讀 28,503評論 9 295
  • 開發(fā)前需準備 1:申請微信公眾號 和 微信小程序泽本,這是兩個不同的東西,都需要單獨申請姻僧、不同的帳號规丽; 2:微信公眾號...
    zx一個胖子閱讀 4,042評論 5 1
  • 上個月8號蒲牧,早上鬧肚子6點就醒了,被折騰得睡不著嘁捷,刷朋友圈看到尚潔怡轉了一個H5的場景廣告《有一種騙子造成,叫爸爸》:...
    小松鼠閱讀 1,488評論 0 4
  • Docker容器抓包說明: https://m.aliyun.com/yunqi/articles/272277?...
    Freeneryang閱讀 191評論 0 0
  • 眾籌一種起源于美國的互聯(lián)網融資模式。最早將其引入中國的是“點名時間”雄嚣,因東西方文化和環(huán)境的差異變得水土不服晒屎。 但,...
    好學長松哥閱讀 199評論 0 0