php实现第三方平台授权流程

一、微信开放平台注册(进行开发者资质认证)

1.1 注册开放平台账号
在这里插入图片描述

注册账号需要邮箱(这个邮箱贼恶心,不能是微信绑定过的,也不能是公众号平台绑定的,小程序平台绑定的也不行),然后需要提供公司主体等相关的信息

1.2 通过开发者资质认证
在这里插入图片描述

1.3 创建第三方平台
在这里插入图片描述

1.4 完善开发者信息
主要是权限集以及开发资料点击编辑进行配置

在这里插入图片描述
在这里插入图片描述

二、开发流程

在这里插入图片描述
步骤 说明
2.1、配置授权事件URL,用于接收component_verify_ticket 出于安全考虑,在第三方平台创建审核通过后,微信服务器 每隔 10 分钟会向第三方的消息接收地址推送一次 component_verify_ticket,用于获取第三方平台接口调用凭据。component_verify_ticket有效期为12h

  // 授权事件接受地址
    
    public function authorization(){
       
      if (!$xml = file_get_contents('php://input')) {
          error_log("\msg:无参数\n",   3,   "./wxNotify.log");
        }
        
        $data = fromXml($xml); 
        Cache::set('component_verify_ticket',$data['Encrypt'],3600);
        echo 'success';
    }

2.2、获得component_verify_ticket后,按照获取第三方平台 component_access_token 接口文档,调用接口获取component_access_token component_access_token有效期2h,当遭遇异常没有及时收到component_verify_ticket时,建议以上一次可用的component_verify_ticket继续生成component_access_token。避免出现因为 component_verify_ticket 接收失败而无法更新 component_access_token 的情况。

   /*接口文档 /授权相关接口 /获取令牌*/
    public function get_component_access_token(){
        if (Cache::has('ComponentAccessToken')) {
            return Cache::get('ComponentAccessToken');
        }
        $url = 'https://api.weixin.qq.com/cgi-bin/component/api_component_token';
        $parmas = array();
        $parmas['component_appid'] = $this->component_appid;
        $parmas['component_appsecret'] = $this->component_appsecret;
        $ticket = Cache::get('component_verify_ticket');
        $sa  = decryptMsg($ticket);
        $saArr = fromXml($sa); 
        $ticket = $saArr['ComponentVerifyTicket'];
        $parmas['component_verify_ticket'] = $ticket;
        $result = curlPost($url,json_encode($parmas));
        $result = json_decode( $result, true );
        if (!$result) {
            return false;
        }
        $expire = $result['expires_in'] ? intval($result['expires_in']) : 7200;
        Cache::set('ComponentAccessToken', $result['component_access_token'], $expire);
        return $result['component_access_token'];
    }

2.3、获得component_access_token后,按照获取预授权码 pre_auth_code接口文档 ,调接口获取pre_auth_code 用于生成扫码授权二维码或者链接需要的pre_auth_code

 /**
     * 获取预授权码
     */
    public  function getPreAuthCode()
    {
        if (Cache::has('PreAuthCode')) {
           
            return Cache::get('PreAuthCode');
        }

        $component_access_token = $this->get_component_access_token();
        $app_id =$this->component_appid;

        $url =  'https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=' . $component_access_token;
        $data = [
            'component_appid' => $app_id
        ];
         $result = curlPost($url,json_encode($data));
         $result = json_decode( $result, true );
       
        if ($result) {
 
            $expires_in = $result['expires_in'];
            Cache::set('PreAuthCode', $result['pre_auth_code'], $expires_in* 0.9);
            return $result['pre_auth_code'];
        }
        return false;
    }

2.4、获得pre_auth_code后,按照授权技术流程说明文档 ,引导用户授权后获取authorization_code authorization_code有过期时间,该过期时间在授权后回调 URI进行返回;也会通过推送授权变更通知的方式将authorization_code推送给第三方平台

  /****
     * 授权页面
    * */
     public function jump(){
         Cache::rm('PreAuthCode');
         $a = $this->getPreAuthCode();
         $url = 'https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=3&no_scan=1&component_appid='.$this->component_appid.'&pre_auth_code='.$this->getPreAuthCode().'&redirect_uri=https://assistant.txwluo.com/index.php/api/index/redirect&auth_type=3&biz_appid=xxxx#wechat_redirect';
         header('location:'.$url);exit;
     }
     //获取授权后回调 授权token
     public function redirect(){
         
         $authorization_code = $_GET['auth_code'];
         $expires_in = $_GET['expires_in'];
        
         Cache::set('authorization_code', $authorization_code, $expires_in* 0.9);
        //  根据授权码获取账号授权信息
         $info = $this->authorizationInfo($authorization_code);
        // 将授权信息存入数据库
         
         echo '授权成功';
     }
   
     

2.5、获得authorization_code后,按照使用授权码换取公众号或小程序的接口调用凭据和授权信息 接口文档 ,调接口获取authorizer_refresh_token 通过授权码和自己的接口调用凭据(component_access_token),换取公众号或小程序的接口调用凭据(authorizer_access_token 和用于前者快过期时用来刷新它的 authorizer_refresh_token)和授权信息(授权了哪些权限等信息)

    /***
      * 
      * 使用授权码换取公众号或小程序的接口调用凭据和授权信息
      **/
     public function authorizationInfo($authorization_code=''){
        $url = 'https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token='.$this->get_component_access_token();
        $parmas = array();
        $parmas['component_appid'] = $this->component_appid;
        $parmas['authorization_code'] = $authorization_code;
        $result = curlPost($url,json_encode($parmas));
        $result = json_decode( $result, true );
        if (!$result) {
            return false;
        }
        if(isset($result['errcode'])){
            echo '授权失败'.$result['errmsg'];die;
        }
        if(isset($result['authorization_info'])){
            $this->authorizerInfo($result['authorization_info']);
        }
        return $result;
     }
  /****
      * 获取授权方的帐号基本信息
      ***/
      public function authorizerInfo($account_info){

        $url = 'https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token='.$this->get_component_access_token();
        $parmas = array();
        $parmas['component_appid'] = $this->component_appid;
        $parmas['authorizer_appid'] =  $account_info['authorizer_appid'];//从数据库读取操作的公众号的appid
        // dump($parmas);
        $result = curlPost($url,json_encode($parmas));
        $result = json_decode( $result, true );
        if (!$result) {
            return false;
        }
        if(isset($result['authorizer_info'])){
            $model = Db::name('account');
            $authorizer_info =  $result['authorizer_info'];
            $authorization_info  =  $result['authorization_info'];
            $insert_data['appid'] = $authorization_info['authorizer_appid'];
            $insert_data['access_token'] = $account_info['authorizer_access_token'];
            $insert_data['refresh_token'] = $authorization_info['authorizer_refresh_token'];

            $insert_data['nick_name'] = $authorizer_info['nick_name'];
            $insert_data['head_image'] = $authorizer_info['head_img'];
            $insert_data['user_name'] = $authorizer_info['user_name'];
            $insert_data['qrcode_image'] = $authorizer_info['qrcode_url'];
            $insert_data['principal_name'] = $authorizer_info['principal_name'];
            $insert_data['signature'] = $authorizer_info['signature'];
            $id = $model->insertGetId($insert_data);
        
        }
        return $result;
        
        
               
        //可以将账号基本信息存数据库
        // Cache::set('api_query_auth', $result, 7200);
        
        // dump(Cache::get('api_query_auth'));
      }
      

2.6、获得authorizer_refresh_token后,按照获取/刷新授权公众号或小程序的接口调用凭据 接口文档 ,调接口获取authorizer_access_token 可通过 authorizer_refresh_token 获取公众号或小程序接口的调用令牌

  //获取令牌tokken
     public function getAuthorizerAccessToken($authorizer_appid='wx25bcc1fc10191be9'){
          if (Cache::has($authorizer_appid.'authorizer_access_token')) {
                 //获取令牌
                 $access_token = Cache::get($authorizer_appid.'authorizer_access_token');
            }else{
                //echo 111;die;
                //刷新凭证并重新存储
                    $url = 'https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token='.$this->get_component_access_token();
                    $parmas = array();
                    $parmas['component_appid'] = $this->component_appid;//微信第三方的appid
                    $parmas['authorizer_appid'] =  $authorizer_appid;//公众号的appid
                    //要将authorizer_refresh_token存入数据库获取完要记得修改
                    $data = Db::name('account')->where(['appid'=>$authorizer_appid])->find();
                    // $parmas['authorizer_refresh_token'] =  'refreshtoken@@@yOEDBPV78uo8VRYSo4vqF0Zbmh8_xL_UjgGLRfgGvmE';
                    $parmas['authorizer_refresh_token'] = $data['refresh_token'];
                    // dump($parmas);
                    $result = curlPost($url,json_encode($parmas));
                    
                    $result = json_decode( $result, true);
                    if (!$result) {
                        return false;
                    }
                    if(isset($result['authorizer_access_token'])){
                        
                        $access_token = $result['authorizer_access_token'];
                        file_put_contents("info.txt","authorizer_refresh_token:".$result['authorizer_refresh_token'].PHP_EOL.'access_token:'.$access_token);
                        Cache::set($authorizer_appid.'authorizer_access_token', $result['authorizer_access_token'], 7100);
                        $data = Db::name('account')->where(['appid'=>$authorizer_appid])->update(['refresh_token'=>$result['authorizer_refresh_token'],'access_token'=>$access_token]);
                    }else{
                         return false;
                    }
                    //将令牌存入数据库 记得刷新
                   
                    
            }
             return $access_token;
     }
     

2.7、按照接口文档,代替公众号或小程序调用接口 在完成授权后,第三方平台可通过公众号或小程序的接口调用凭据(authorizer_access_token)来代替它调用接口,具体请见接口文档

辅助函数

  /**
     * 将xml转为array
     * @param $xml
     * @return mixed
     */
    function fromXml($xml)
    {
        // 禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }
     /*解密ticket*/
    function decryptMsg($msg_encrypt)
    {

        $EncodingAESKey = 'assistanttxwluo1676542519assistanttxwluo167';

        $AESKey = base64_decode($EncodingAESKey.'=');

        $iv = substr($AESKey, 0, 16);

        $msg_decode = base64_decode($msg_encrypt);

        $msg = openssl_decrypt($msg_decode, 'AES-256-CBC', $AESKey, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);

        $msg_len = unpack('N', substr($msg, 16, 4));

        $len = $msg_len[1];

        $xml = substr($msg, 20, $len);



        return $xml;

    }
      
   function curlPost($url, $post_data, $timeout = 5)
    {
        $ch = curl_init();

        if (stripos($url, 'https://') !== false) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_SSLVERSION, 1);
        }

        $header = empty($header) ? '' : $header;

        if (is_string($post_data)) {
            $strPOST = $post_data;
        }
        else {
            $aPOST = array();

            foreach ($post_data as $key => $val) {
                $aPOST[] = $key . '=' . urlencode($val);
            }

            $strPOST = join('&', $aPOST);
        }

        curl_setopt($ch, CURLOPT_HTTP_VERSION, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $strPOST);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        $result = curl_exec($ch);
        $aStatus = curl_getinfo($ch);
        curl_close($ch);

        if (intval($aStatus['http_code']) == 200) {
            return $result;
        }
        else {
            return false;
        }
    }

三、事件接收推送

  // 授权消息与事件接收配置
    
    public function message(){
         
        
        //获取到微信推送过来post数据(xml格式)

    	//2.处理消息类型并设置回复类型和内容
    	
    	//encodingAesKey和token均为申请三方平台是所填写的内容

        $encodingAesKey = $this->encodingAesKey;

        $token =$this->token;
            
        $appId = $this->component_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']);
      
         $pc = new \WXBizMsgCrypt ($token, $encodingAesKey, $appId );
        
        //获取到微信推送过来post数据(xml格式)
        
        $postArr=file_get_contents('php://input');
        // $postArr = $GLOBALS['HTTP_RAW_POST_DATA'];
        file_put_contents('message.txt',$postArr);
        
        $msg = '';
        
        $errCode= $pc->decryptMsg($msg_sign, $timeStamp, $nonce, $postArr,$msg);

        // 解密后,当$errCode返回值为0时,代表解密成功,下一步我们就需要对消息进行解析处理:
        
         $postObjArr =simplexml_load_string($msg,'SimpleXMLElement',LIBXML_NOCDATA);
    
        if(strtolower($postObjArr->MsgType) =='text'){
            //第三方模拟发送
             
             if($postObjArr->Content=='TESTCOMPONENT_MSG_TYPE_TEXT'){
              //回复用户消息
                  $content = 'TESTCOMPONENT_MSG_TYPE_TEXT_callback';
                  echo $this->responseText($postObjArr,$content);
             }
        }
      
        if(strtolower($postObjArr->MsgType) =='event'){
            //如果是扫描带有参数的二维码进入。。。。。。
             if($postObjArr->Event=='SCAN' || $postObjArr->Event=='subscribe'){
                  //回复用户消息
                  $toUser=$postObjArr->FromUserName;
                //   $fromUser=$postObjArr['ToUserName'];
                  $eventKey=$postObjArr->EventKey;
                  $model = Db::name('user_pc');
                  
                  $eventKey = ltrim($eventKey,'qrscene_');
                  $insert_data['user_key'] = $eventKey;
                  $insert_data['openid'] = $toUser;
                  
                  $id = $model->insertGetId($insert_data);
                  echo 'success';
             
               
             }
        }
    
       
        
        
    }
    
    
    
    function responseText($postObj,$content){
             $template ="<xml>
             <ToUserName><![CDATA[%s]]></ToUserName>
             <FromUserName><![CDATA[%s]]></FromUserName>
             <CreateTime>%s</CreateTime>
             <MsgType><![CDATA[%s]]></MsgType>
             <Content><![CDATA[%s]]></Content>
             </xml>";
            
             
             $fromUser = $postObj ->ToUserName;
             $toUser   = $postObj -> FromUserName;
             $time     = time();
             $msgType  = 'text';
                 
             $res =sprintf($template,$toUser,$fromUser,$time,$msgType,$content);
             
             $encodingAesKey = $this->encodingAesKey;

             $token =$this->token;
            
             $appId = $this->component_appid;
            
            
             $pc = new \WXBizMsgCrypt ($token, $encodingAesKey, $appId );
            
             $encryptMsg = '';
           
             $errCode =$pc->encryptMsg($res,$_GET['timestamp'], $_GET['nonce'], $encryptMsg);
            
             if ($errCode == 0) {
                
                return $encryptMsg;
            }
            
             return $a;

        }
    
    

引用文件地址:
链接: https://pan.baidu.com/s/1Ef2j8nqaBWptZq5LmeRkSg?pwd=88dq 提取码: 88dq 复制这段内容后打开百度网盘手机App,操作更方便哦

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值