微信jssdk踩坑 vue前端+php后端生成签名

Daming 2019-05-09
0条评论 802 次浏览
Daming 2019-05-090条评论 802 次浏览

前端Vue(VUX) ,后端PHP(TP3)

微信jssdk文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

先生成微信开发者测试号的appid 与appsecret

根据文档引入 jssdk(我前端用的是vux ui框架  使用的是他封装好了的jssdk)

因为在做前后端分离项目,所以 需要异步请求后台获取 config

前端代码如下:

let url =encodeURIComponent(window.location.href.split('#')[0]);//后台生成签名 需要前端页面的url   使用encodeUPIComponent处理并去去除#号后面的哈希

Vue.http.get('http://xxxx.cn/wechat/base/getJssdkConfig?url=' + url).then((res) => {
  let wxdata = res.data;
  wxdata.debug = true;
  wxdata.jsApiList = [
    // 所有要调用的 API 都要加到这个列表中
    'onMenuShareTimeline',//分享到朋友圈
    'onMenuShareAppMessage',//分享给朋友
    'onMenuShareQQ',//分享到QQ
    'onMenuShareQZone',//分享到QQ空间
    'onMenuShareWeibo'//分享到腾讯微博
  ];
  Vue.wechat.config(wxdata);
  // console.log(wxdata);
});
Vue.wechat.ready((e) => {
  console.log("okokok");
});
Vue.wechat.error(function (res) {
  console.log(res);
  // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});

后端接口代码:

<?php

namespace WeChat\Controller;

use Think\Controller;

class BaseController extends Controller
{
    protected $token;
    protected $ticket;
    protected $url;
    protected $signPackage;

    public function _initialize(){
        //处理跨域问题
        header('Content-Type:application/json; charset=utf-8');
        header('Access-Control-Allow-Origin:*');
        header('Access-Control-Max-Age:86400'); // 允许访问的有效期
        header('Access-Control-Allow-Headers:*');
        header('Access-Control-Allow-Methods:OPTIONS, GET, POST, DELETE');
    }

    public function index()
    {
        echo "wechat";
    }



    private function httpGet($url)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 500);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); //ssl不验证证书下同
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); //ssl不验证
        $res = curl_exec($curl);
        curl_close($curl);
        return $res;
    }


    /**
     * @param string $url  
     */
    public function getJssdkConfig($url = "")
    {
//        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
//        $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $this->getAccessToken();//获取toekn
        $this->getJsApiTicket();//获取ticket
        $this->generateSignature();//生成签名
        $this->ajaxReturn($this->signPackage);//返回配置给前端

    }


    /**
     * 从微信服务器或数据库缓存中获取token
     */
    protected function getAccessToken()
    {

        $token = M('accesstoken')->limit(1)->find();
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . C('wechat_appid') . "&secret=" . C('wechat_appsecret');


        if ($token) {

            $token['time'] = (int)$token['time'];
            $token['expires_in'] = (int)$token['expires_in'];

            //如果数据库中的token存放+过期时间 小于了当前时间  更新token
            if ($token['time'] + $token['expires_in'] < time()) {
                //更新
                $returnData = json_decode($this->httpGet($url));
                $resData['access_token'] = $returnData->access_token;
                $resData['expires_in'] = (string)$returnData->expires_in;
                $resData['time'] = (string)time();
                M('accesstoken')->where(array('id' => $token['id']))->save($resData);
                $res = $resData;
                $res['source'] = "update";
            } else {
                //缓存
                $res = $token;
                $res['source'] = "cache";
            }

        } else {
            //新增
            $returnData = json_decode($this->httpGet($url));
            $resData['access_token'] = $returnData->access_token;
            $resData['expires_in'] = (string)$returnData->expires_in;
            $resData['time'] = (string)time();
            M('accesstoken')->add($resData);
            $res = $resData;
            $res['source'] = "new";
        }

        $this->token = $res;

    }

    /**
     * 从微信服务器或数据库缓存中获取ticket
     */
    protected function getJsApiTicket()
    {

        $ticket = M('jsticket')->limit(1)->find();
        $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $this->token['access_token'] . '&type=jsapi';


        if ($ticket) {

            $ticket['time'] = (int)$ticket['time'];
            $ticket['errcode'] = (int)$ticket['errcode'];
            $ticket['expires_in'] = (int)$ticket['expires_in'];
            if ($ticket['time'] + $ticket['expires_in'] < time()) {
                //更新

                $returnData = json_decode($this->httpGet($url));
                $resData['ticket'] = $returnData->ticket;
                $resData['errmsg'] = $returnData->errmsg;
                $resData['errcode'] = $returnData->errcode;
                $resData['expires_in'] = $returnData->expires_in;
                $resData['time'] = time();
                M('jsticket')->where(array('id' => $ticket['id']))->save($resData);
                $res = $resData;
                $res['source'] = "update";
            } else {
                //缓存
                $res = $ticket;
                $res['source'] = "cache";
            }

        } else {
            //新增
            $returnData = json_decode($this->httpGet($url));
            $resData['ticket'] = $returnData->ticket;
            $resData['errmsg'] = $returnData->errmsg;
            $resData['errcode'] = $returnData->errcode;
            $resData['expires_in'] = $returnData->expires_in;
            $resData['time'] = time();
            M('jsticket')->add($resData);
            $res = $resData;
            $res['source'] = "new";
        }

        $this->ticket = $res;

    }

    /**
     * 生成签名数据包
     */
    protected function generateSignature()
    {

        $noncestr = 'crazyming' . time();
        $jsapi_ticket = $this->ticket['ticket'];
        $timestamp = time();
        $url = $this->url;
        $string = "jsapi_ticket=" . $this->ticket['ticket'] . "&noncestr=$noncestr&timestamp=$timestamp&url=$url";
        $signature = sha1($string);

        $signPackage = array(
            "appId" => C('wechat_appid'),
            "nonceStr" => $noncestr,
            "timestamp" => $timestamp,
            "url" => $url,
            "signature" => $signature,
            "ticket" => $jsapi_ticket,
            "token" => $this->token['access_token']
        );

        $this->signPackage = $signPackage;
    }


}

如提示invalid url domain:

当前页面所在域名与使用的appid没有绑定,请确认正确填写绑定的域名,仅支持80(http)和443(https)两个端口,因此不需要填写端口号

例如:

如提示invalid signature 请检查:

1.确认签名算法正确,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。

2.确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。

3.确认url是页面完整的url(请在当前页面alert(location.href.split(‘#’)[0])确认),包括’http(s)://’部分,以及’?’后面的GET参数部分,但不包括’#’hash后面的部分。

4.确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。

5.确保一定缓存access_token和jsapi_ticket。

6.确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去’#’hash部分的链接(可用location.href.split(‘#’)[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。

1+

发表评论

电子邮件地址不会被公开。