PHP微信三方平台-授权登录

一、逻辑步骤解析

步骤 1:第三方平台方获取预授权码(pre_auth_code)

步骤 2:引入用户进入授权页

第三方平台方可以在自己的网站中放置“微信公众号授权”或者“小程序授权”的入口,或生成授权链接放置在移动网页中,引导公众号和小程序管理员进入授权页。

方式一:授权注册页面扫码授权

授权页网址为:

https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=xxxx&pre_auth_code=xxxxx&redirect_uri=xxxx&auth_type=xxx。

参数

必填

参数说明

component_appid

第三方平台方 appid

pre_auth_code

预授权码

redirect_uri

回调 URI

auth_type

要授权的帐号类型, 1 则商户扫码后,手机端仅展示公众号、2 表示仅展示小程序,3 表示公众号和小程序都展示。如果为未指定,则默认小程序和公众号都展示。第三方平台开发者可以使用本字段来控制授权的帐号类型。

biz_appid

指定授权唯一的小程序或公众号

 

 二、代码实现

wx_tools 工具文件

 /**
     * 以post方式提交xml到对应的接口url
     * @param string $url 提交地址
     * @param string $param 需要post的xml数据
     * @param bool $file 是否上传文件
     * @param bool|array $cert 是否需要证书,默认不需要 如果是数组代表有证书地址 请按以下格式 array('cert' => 'cert.pem', 'key' => 'key.pem', 'rootca' => 'rootca.pem');
     * @param int $second
     * @return mixed
     */
    public static function postCurl($url, $param, $file = false, $cert = false, $second = 30)
    {
        $curl = curl_init();
        //设置超时
        curl_setopt($curl, CURLOPT_TIMEOUT, $second);
        if (stripos($url, "https://") !== FALSE) {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($curl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
        }
        if (PHP_VERSION_ID >= 50500 && class_exists('\CURLFile')) {
            $is_file = true;
        } else {
            $is_file = false;
            if (defined('CURLOPT_SAFE_UPLOAD')) {
                curl_setopt($curl, CURLOPT_SAFE_UPLOAD, false);
            }
        }
        if (is_string($param)) {
            $str_post = $param;
        } elseif ($file) {
            if ($is_file) {
                foreach ($param as $key => $val) {
                    if (substr($val, 0, 1) == '@') {
                        $param[$key] = new \CURLFile(realpath(substr($val, 1)));
                    }
                }
            }
            $str_post = $param;
        } else {
            $post = array();
            foreach ($param as $key => $val) {
                $post[] = $key . "=" . urlencode($val);
            }
            $str_post = join("&", $post);
        }

        //设置证书 todo 未验证
        if (is_array($cert)) {
            //请确保您的libcurl版本是否支持双向认证,版本高于7.20.1 使用证书:cert 与 key 分别属于两个.pem文件
            curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($curl, CURLOPT_SSLCERT, $cert['cert']);
            curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($curl, CURLOPT_SSLKEY, $cert['key']);
            //红包使用
            if (empty($cert['rootca'])) {
                curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
                curl_setopt($curl, CURLOPT_CAINFO, $cert['rootca']);
            }
        }

        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $str_post);
        $content = curl_exec($curl);
        $status = curl_getinfo($curl);
        if (intval($status["http_code"]) == 200) {
            curl_close($curl);
//            ApiLog::setMessage(\Yii::$app->session->get('request_base_api_log_id'),['url' => $url, 'message'=> $content], 1);
            return $content;
        } else {
            $error = curl_errno($curl);
            curl_close($curl);
//            $this->err_code = $error;
//            $this->err_msg = $this->curl_error[$error];
//            ApiLog::setMessage(\Yii::$app->session->get('request_base_api_log_id'),['url' => $url, 'message'=> $content], 0);
            return false;
        }
    }


    /**
     * CURL GET 请求
     * @param $url
     * @return bool|mixed
     */
    public static function getCurl($url)
    {
        $curl = curl_init();
        if (stripos($url, "https://") !== FALSE) {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
            curl_setopt($curl, CURLOPT_SSLVERSION, 1); //CURL_SSLVERSION_TLSv1
        }
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $content = curl_exec($curl);
        $status = curl_getinfo($curl);

        if (intval($status["http_code"]) == 200) {
            curl_close($curl);
//            ApiLog::setMessage(\Yii::$app->session->get('request_base_api_log_id'),['url' => $url, 'message'=> $content], 1);
            return $content;
        } else {
            $error = curl_errno($curl);
            curl_close($curl);
            file_put_contents('../web/logs/notify/error' . date('YmdHi') . '.txt', $error);
//            ApiLog::setMessage(\Yii::$app->session->get('request_base_api_log_id'),['url' => $url, 'message'=> $content], 0);
//            $this->err_code = $error;
//            $this->err_msg = $this->curl_error[$error];
            return false;
        }
    }
View Code

1、获取pre_auth_code(通过component_access_token)

2、获取component_access_token(通过component_verify_ticek)

3、component_verify_tick(通过三方平台填写后台授权回到地址【10分钟微信推送】)

/**
     * 获取component_access_token
     * @return bool|mixed
     */
    public static function getComponentAccessToken()
    {
        if (\Yii::$app->cache->exists(self::ComponentAccessToken)) {
            return \Yii::$app->cache->get(self::ComponentAccessToken);
        }

        $app_id = \Yii::$app->params['app_id'];
        $app_secret = \Yii::$app->params['app_secret'];
        $component_verify_ticket = self::getComponentVerifyTicket();

        $url = 'https://api.weixin.qq.com/cgi-bin/component/api_component_token';
        $data = [
            'component_appid' => $app_id,
            'component_appsecret' => $app_secret,
            'component_verify_ticket' => $component_verify_ticket
        ];

        $json = null;
        $result = wx_tools::postCurl($url, wx_tools::jsonEncode($data));
        if ($result) {
            $json = wx_tools::parseData($result);
            if (!$json) {
                return false;
            }
        }
        $component_access_token = $json['component_access_token'];
        $expire = $json['expires_in'] ? intval($json['expires_in']) : 7200;
        \Yii::$app->cache->set(self::ComponentAccessToken, $component_access_token, $expire * 0.9);

        return $component_access_token;
    }



  /**
     * 获取预授权码
     */
    public static function getPreAuthCode()
    {
        if (\Yii::$app->cache->exists(self::PreAuthCode)) {
            return \Yii::$app->cache->get(self::PreAuthCode);
        }

        $component_access_token = self::getComponentAccessToken();
        $app_id = \Yii::$app->params['app_id'];

        $url =  'https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=' . $component_access_token;
        $data = [
            'component_appid' => $app_id
        ];
        $result = wx_tools::postCurl($url, wx_tools::jsonEncode($data));

        $json = null;
        if ($result) {
            $json = wx_tools::parseData($result);
            if (!$json) {
                return false;
            }
            $pre_auth_code = $json['pre_auth_code'];
            $expires_in = $json['expires_in'];
            \Yii::$app->cache->set(self::PreAuthCode, $pre_auth_code, $expires_in * 0.9);
            return $pre_auth_code;
        }
        return false;
    }

 

三方授权事件代码

 /**
     * 三方授权事件接收
     */
    public function actionNotify()
    {
//        file_put_contents('../web/logs/notify/notify'.date('YmdHi').'.txt','微信服务器进来的');
        $data = file_get_contents('php://input');
//        file_put_contents('../web/logs/notify/data'.date('YmdHi').'.txt',$data);
//        file_put_contents('../web/logs/notify/get'.date('YmdHi').'.txt',json_encode($_GET));
        if ($data) {
            $time_stamp = empty($_GET['timestamp']) ? "" : trim($_GET['timestamp']);
            $nonce = empty($_GET['nonce']) ? "" : trim($_GET['nonce']);
            $msg_sign = empty($_GET['msg_signature']) ? "" : trim($_GET['msg_signature']);

            if (!$time_stamp || !$nonce || !$msg_sign) {
//                Log::ERROR('缺少time_stamp,nonce,msg_sign中任一项');
                exit;
            }

            $app_id = \Yii::$app->params['app_id'];
            $token = \Yii::$app->params['token'];
            $encodingAesKey = \Yii::$app->params['encoding_aes_key'];

            $wx_biz = new WXBizMsgCrypt($token, $encodingAesKey, $app_id);
            $response = '';
            $err_code = $wx_biz->decryptMsg($msg_sign, $time_stamp, $nonce, $data, $response);
            if ($err_code == 0) {
                $response = Tools::xmlToArray($response);
                $info_type = $response['InfoType'];

                switch ($info_type) {
                    case 'component_verify_ticket':
//                        Log::INFO('create component_verify_ticket');
                        //保存到缓存
                        wx_auth::saveComponentVerifyTicket($response['ComponentVerifyTicket']);
                        //TODO
                        break;
                    case 'authorized':
                        //TODO
                        break;
                    case 'unauthorized';
                        //TODO 取消授权
                        WxPlatform::updateAuthStatus($response['AuthorizerAppid']);
                        wx_auth::clearAuthorizerAccessToken($response['AuthorizerAppid']);
                        break;
                    case 'updateauthorized':
                        //TODO
                        break;
                }

                exit('success');
            } else {
                ApiLog::setMessage(\Yii::$app->session->get(self::RequestBaseApiLogId), $data, 0);
//                Log::ERROR('解密失败:' . $err_code);
                exit('fail');
            }
        }
        ApiLog::setMessage(\Yii::$app->session->get(self::RequestBaseApiLogId), '非微信服务器操作', 0);
//        Log::ERROR('非微信服务器操作');
        exit;
    }

 4、生成页面URL

    /**
     * 公众号授权三方平台页面
     * @return string
     */
    public function actionBind()
    {
        $params='';//可以带的参数
        $redirect_uri = \Yii::$app->request->hostInfo . \Yii::$app->request->scriptUrl . '/public-signal/bind-call-back' . '?params=' . $params;
        $app_id = \Yii::$app->params['app_id'];
        $url = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=" . $app_id . "&pre_auth_code=" . $pre_auth_code . "&redirect_uri=" . $redirect_uri;
        return $this->render('index', [
            'url' => $url
        ]);
    }
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>授权页</title>
</head>
<body>

<a href="<?=$url?>" id="authurl" style="display: inline;">
    <img src="https://open.weixin.qq.com/zh_CN/htmledition/res/assets/res-design-download/icon_button3_1.png">
</a>
</body>
</html>
 /**
     * 公众号授权三方平台回调地址 完成自己的业务功能
     * @return string|void
     */
    public function actionBindCallBack()
    {
        $request = \Yii::$app->request;
        $params = explode(',', $request->get('params'));

        $auth_code = $request->get('auth_code');
      
    }

 

posted @ 2020-05-18 15:03  鲜花满月楼  阅读(1240)  评论(0编辑  收藏  举报