微信第三方平台授权开发

分享一下微信的第三方平台授权吧,中间还是有挺多坑的,开发前一定要仔细的看几遍文档

一、首先在微信申请成为第三方,流程按着微信提示的走就好了

二、开发授权

1、接收 微信的推送 component_verify_ticket 协议

在第三方平台创建审核通过后,微信服务器会向其“授权事件接收URL”每隔10分钟定时推送component_verify_ticket。第三方平台方在收到ticket推送后也需进行解密(详细请见【消息加解密接入指引】),接收到后必须直接返回字符串success。
点进【消息加解密接入指引】后,下载SDK包,在项目中引入,我就用ThinkPHP5举例了
将php包放到 /extend/Wxapi/

微信SDK包位置

<?php
/**
 * 三方平台微信授权
 *
 */
namespace app\home\controller\api;

use think\Controller;
use think\Db;
use Endroid\QrCode\QrCode;
use think\Loader;

Loader::import('Wxapi.wx', EXTEND_PATH, '.BizMsgCrypt.php');
class Wxapi extends Controller
{
    function __construct()
    {
        parent::__construct();
        $this->token          = '自己的token';
        $this->encodingAesKey = '自己的encodingAesKey ';
        $this->appid          = 'appid';
        $this->appsecret      = 'appsecret';
    }
    //1、接收component_verify_ticket协议
    public function Accredit()
    {
        $token = $this->token;
        $encodingAesKey = $this->encodingAesKey;
        $appId = $this->appid;
    
        $pc = new \WXBizMsgCrypt($token, $encodingAesKey, $appId);
        
        $timeStamp  = empty($_GET['timestamp'])     ? ""    : trim($_GET['timestamp']) ;
        $nonce      = empty($_GET['nonce'])     ? ""    : trim($_GET['nonce']) ;
        $msg_sign   = empty($_GET['msg_signature']) ? ""    : trim($_GET['msg_signature']) ;
        $encryptMsg = file_get_contents('php://input');
        echo 'success';
        $xml_tree = new \DOMDocument();
        $xml_tree->loadXML($encryptMsg);
        $array_e = $xml_tree->getElementsByTagName('Encrypt');
        $encrypt = $array_e->item(0)->nodeValue;


        $format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%s]]></Encrypt></xml>";
        $from_xml = sprintf($format, $encrypt);
        $this->logResult('/form.log', $from_xml);
        // 第三方收到公众号平台发送的消息
        $msg = '';
        $errCode = $pc->decryptMsg($msg_sign, $timeStamp, $nonce, $from_xml, $msg);
        if ($errCode == 0) {
            //print("解密后: " . $msg . "\n");
            $xml = new \DOMDocument();
            $xml->loadXML($msg);
            $array_e = $xml->getElementsByTagName('ComponentVerifyTicket');
            $component_verify_ticket = $array_e->item(0)->nodeValue;
            $arr['wxtoken'] = $component_verify_ticket;
            $arr['type'] = 1;
            $arr['effective'] = time()+300; 
            $res = Db::table('wxtoken')->where('id',1)->update($arr);
            file_put_contents(EXTEND_PATH.'/ticket.log', $component_verify_ticket);
            // $this->logResult('/msgmsg.log','解密后的component_verify_ticket是:'.$component_verify_ticket);

            $msgObj = simplexml_load_string($msg, 'SimpleXMLElement', LIBXML_NOCDATA);
            $content = trim($msgObj->Content);
 
            //第三方平台全网发布检测普通文本消息测试 
            if (strtolower($msgObj->MsgType) == 'text' && $content == 'TESTCOMPONENT_MSG_TYPE_TEXT') {
                $toUsername = trim($msgObj->ToUserName);
                if ($toUsername == 'gh_3c884a361561') { 
                    $content = 'TESTCOMPONENT_MSG_TYPE_TEXT_callback'; 
                    echo $this->responseText($msgObj, $content);
                }
            }
            //第三方平台全网发布检测返回api文本消息测试 
            if (strpos($content, 'QUERY_AUTH_CODE') !== false) { 
                $toUsername = trim($msgObj->ToUserName);
                if ($toUsername == 'gh_3c884a361561') { 
                    $query_auth_code = str_replace('QUERY_AUTH_CODE:', '', $content);
                    $params = $this->dedeLogic->api_query_auth($query_auth_code);
                    $authorizer_access_token = $params['authorization_info']['authorizer_access_token']; 
                    $content = "{$query_auth_code}_from_api"; 
                    $this->sendServiceText($msgObj, $content, $authorizer_access_token);
                }
            }
            return 'success';
        } else {
            $this->logResult('/error.log','解密后失败:'.$errCode);
            print($errCode . "\n");
        }
    }

2、获取第三方平台component_access_token

/**
     *  2、获取第三方平台component_access_token 
     */
    function GetComponent(){
        $verify_ticket = Db::table('wxtoken')->where('id',1)->find();
        $component =$verify_ticket['wxtoken']; 
        $url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";
        $data = array(
                    "component_appid"=>$this->appid,
                    "component_appsecret"=>$this->appsecret,
                    "component_verify_ticket"=>$component
                );
        $send_result = $this->httpRequest($url,'POST',json_encode($data));
        $send_result = json_decode($send_result,true);
        $component_access_token = empty($send_result['component_access_token']) ? "" : trim($send_result['component_access_token']);
        $arr['wxtoken'] = $component_access_token;
        $arr['type'] = 2;
        $arr['effective'] = time()+6600; 
        $res = Db::table('wxtoken')->where('id',2)->update($arr);
        // var_dump($send_result);
        return $component_access_token;
    }

3、获取预授权码pre_auth_code

    /**
     *  3、获取预授权码pre_auth_code
     */
    private function Precode(){
        $data = Db::table('wxtoken')->where('id','3')->find();
        if(!empty($data) && $data['effective']<=time()){

            $component = Db::table('wxtoken')->where('id',2)->find();
            if(!empty($component) && $component['effective']>time()){
                $token = $component['wxtoken'];
            }else{
                $token = $this->GetComponent();
            }
            $url = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token={$token}";
            $data = array(
                        "component_appid"=>$this->appid
                    );
            $send_result = $this->httpRequest($url,'POST',json_encode($data));
            $send_result = json_decode($send_result,true);
            $arr['wxtoken'] = empty($send_result['pre_auth_code']) ? '': trim($send_result['pre_auth_code']);
            $arr['type'] = 3;
            $arr['effective'] = time()+600; 
            $res = Db::table('wxtoken')->where('id','3')->update($arr);
            // var_dump($send_result);
            return $arr['wxtoken'];
        }else{
            return $data['wxtoken'];
        }
        
    }

4、使用预授权码换取用户授权码

    // 4、第四步前一半,返回用户授权二维码
    public function qrcode($vid)
    {
        $appid = $this->appid;
        $precode = $this->Precode();
        $redirect_uri = 'xxxx.com/home/miniapp/succeed?vid='.$vid; //授权后回调传值地址
        $qrCode=new QrCode();
        //电脑网页端验证
        $url = 'https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid='.$appid.'&pre_auth_code='.$precode.'&redirect_uri='.$redirect_uri.'&auth_type=2';
        return $url;
     }

    /**
     *  4、第四步的后一半,用户授权后回调地址 
     *  授权后回调URI,得到授权码(authorization_code)和过期时间
     *  第三方平台获取到的该小程序授权的authorizer_access_token
     */ 
    function Succeed(){
        $map['vid'] = input('get.vid');
        $authorization_code = empty($_GET['auth_code']) ? "" : trim($_GET['auth_code']);
        $expires_in = empty($_GET['expires_in']) ? '' : (trim($_GET['expires_in'])+time());
        $map['wxtoken'] = $authorization_code;
        $map['effective'] = $expires_in;
        //这里是把授权信息存储起来
        $res = Db::table('wxtoken')->where('vid',$map['vid'])->find();
        if($res){
            $test = Db::table('wxtoken')->where('vid',$map['vid'])->update($map);
        }else{
            $test = Db::table('wxtoken')->insert($map);
        }
        if($res && $test){
            $result = '授权成功';
        }else{
            $result = '授权失败';
        }
        $this->assign('result',$result);
        return $this->fetch('accredit');
    }

5、使用授权码换取公众号或小程序的接口调用凭据和授权信息

     /**
     *  5、使用授权码换取公众号或小程序的接口调用凭据和授权信息
     *  微信授权文档中4
     *  获取authorizer_access_token和authorizer_refresh_token
     */
    public function get_authorizer_token($vid){
        if(empty($vid)){return false; }
        //第三方平台appid
        $appid = $this->appid;
        //获取用户授权码 authorization_code
        $auth_code_value = Db::table('wxtoken')->where('vid',$vid)->find();

        //获取 component_access_token 
        $component = Db::table('wxtoken')->where('id',2)->find();
        if(!empty($component) && $component['effective']>time()){
            $token = $component['wxtoken'];
        }else{
            $token = $this->GetComponent();
        }

        // var_dump($auth_code_value);die;
        if(empty($auth_code_value)) { 
            return 1; //没有授权码
        }
        if($auth_code_value['effective'] < time()){
            //授权码过期 , 用令牌去刷新authorizer_access_token
            $authorizer_access_token = $this->refresh_code($appid,$token);
            return $authorizer_access_token;
        }else{
            $auth_code_value = $auth_code_value['wxtoken'];
        }
        
        $url = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=$token";
        $data = array(
            "component_appid"=>"$appid",
            "authorization_code"=>"$auth_code_value"
        );
        $authorizerData = $this->httpRequest($url,'POST',json_encode($data));
        //授权成功后json串
        // $authorizerData = '{"authorization_info":{"authorizer_appid":"wxc756dcabc3f745a0","authorizer_access_token":"16_VTixr87SXLN0VElDCXLEQatq7aPoG_JXAaWoAnGfe8eFeZELbx8PmVbswUwqG9UQSh3BYPinvUejWlG1JKlaOttOX3h9EGgV5KTrggN3bRpU4EQUpzqh-xGTNdUMQousIg0adK8MYePXwRBOPFTdAEDCSG","expires_in":7200,"authorizer_refresh_token":"refreshtoken@@@-XgUNiQhWcCugsXx9Dh-tOPQK_JL-o3yepI4wto2wmw","func_info":[{"funcscope_category":{"id":17}},{"funcscope_category":{"id":18},"confirm_info":{"need_confirm":0,"already_confirm":0,"can_confirm":0}},{"funcscope_category":{"id":19}},{"funcscope_category":{"id":25},"confirm_info":{"need_confirm":0,"already_confirm":0,"can_confirm":0}},{"funcscope_category":{"id":30},"confirm_info":{"need_confirm":0,"already_confirm":0,"can_confirm":0}},{"funcscope_category":{"id":31},"confirm_info":{"need_confirm":0,"already_confirm":0,"can_confirm":0}},{"funcscope_category":{"id":37}},{"funcscope_category":{"id":40}}]}}';
        $test = json_decode($authorizerData,true);
        if(array_key_exists('authorization_info', $test)){
            $test  = $test['authorization_info'];
            $arr['component_appid'] = $appid;
            $arr['authorizer_appid'] = $test['authorizer_appid'];
            $arr['authorizer_access_token'] = $test['authorizer_access_token'];
            $arr['expires_in'] = intval($test['expires_in'])+time();//有效期2H
            $arr['authorizer_refresh_token'] = $test['authorizer_refresh_token'];
            $arr['func_info'] = '';
            $res = Db::name('miniapp_accredit')->insert($arr);
            return $test;
        }else{
            return false;
        }
        
    }

用户授权的授权码有效期为10分钟,过期后刷新

    /**
     *  用户授权的授权码有效期为10分钟,过期后刷新
     *  获取(刷新)授权公众号或小程序的接口调用凭据(令牌)
     *  component_appid 第三方平台appid
     *  authorizer_appid 授权方appid
     *  authorizer_refresh_token 授权方的刷新令牌
     */
    public function refresh_code($appid,$token){
        $tokens = Db::name('miniapp_accredit')->where('component_appid',$appid)->find();
        if(empty($tokens)){
            //没有存放用户刷新令牌,只能重新授权
            echo '没有存放用户刷新令牌,只能重新授权';
            return false;
        }elseif($tokens['expires_in'] > time()){
            //还在有效期
            return $tokens;
        }
        $url = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=$token";
        $data = array(
            "component_appid"=>"$appid",
            "authorizer_appid"=>$tokens['authorizer_appid'],
            "authorizer_refresh_token"=>$tokens['authorizer_refresh_token'],
        );
        $authorizerData = $this->httpRequest($url,'POST',json_encode($data));
        $test = json_decode($authorizerData,true);
        if($test){
            $arr['authorizer_access_token'] = $test['authorizer_access_token'];
            $arr['expires_in'] = intval($test['expires_in'])+time();//有效期2H
            $arr['authorizer_refresh_token'] = $test['authorizer_refresh_token'];
            $res = Db::table('miniapp_accredit')->where('id',$tokens['id'])->update($arr);
            unset($arr);
        }
        $test['authorizer_appid'] = $tokens['authorizer_appid'];
        return $test;
    }

CURL请求

    /**
     * CURL请求
     * @param $url 请求url地址
     * @param $method 请求方法 get post
     * @param null $postfields post数据数组
     * @param array $headers 请求header信息
     * @param bool|false $debug  调试开启 默认false
     * @return mixed
     */
    function httpRequest($url, $method="GET", $postfields = null, $headers = array(), $debug = false) {
        $method = strtoupper($method);
        $ci = curl_init();
        /* Curl settings */
        curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
        curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 60); /* 在发起连接前等待的时间,如果设置为0,则无限等待 */
        curl_setopt($ci, CURLOPT_TIMEOUT, 7); /* 设置cURL允许执行的最长秒数 */
        curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
        switch ($method) {
            case "POST":
                curl_setopt($ci, CURLOPT_POST, true);
                if (!empty($postfields)) {
                    $tmpdatastr = is_array($postfields) ? http_build_query($postfields) : $postfields;
                    curl_setopt($ci, CURLOPT_POSTFIELDS, $tmpdatastr);
                }
                break;
            default:
                curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
                break;
        }
        $ssl = preg_match('/^https:\/\//i',$url) ? TRUE : FALSE;
        curl_setopt($ci, CURLOPT_URL, $url);
        if($ssl){
            curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
            curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, FALSE); // 不从证书中检查SSL加密算法是否存在
        }
        //curl_setopt($ci, CURLOPT_HEADER, true); /*启用时会将头文件的信息作为数据流输出*/
        curl_setopt($ci, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ci, CURLOPT_MAXREDIRS, 2);/*指定最多的HTTP重定向的数量,这个选项是和CURLOPT_FOLLOWLOCATION一起使用的*/
        curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ci, CURLINFO_HEADER_OUT, true);
        /*curl_setopt($ci, CURLOPT_COOKIE, $Cookiestr); * *COOKIE带过去** */
        $response = curl_exec($ci);
        $requestinfo = curl_getinfo($ci);
        $http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
        if ($debug) {
            echo "=====post data======\r\n";
            var_dump($postfields);
            echo "=====info===== \r\n";
            print_r($requestinfo);
            echo "=====response=====\r\n";
            print_r($response);
        }
        curl_close($ci);
        return $response;
        //return array($http_code, $response,$requestinfo);
    }

喜欢的朋友可以点击喜欢和收藏,如果转载请注明出处https://www.jianshu.com/p/dd6c4be503f0

上面就是全部授权内容了,感觉有帮助的,关注一下

推荐阅读更多精彩内容