一、逻辑步骤解析

步骤 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;
}
}

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'); }

PHP微信三方平台-授权登录的更多相关文章

  1. 【tp5.1】微信公众号授权登录及获取信息录入数据库

    微信公众号开发文档链接:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432 微信公众号授权登录分为两种: 1.以 ...

  2. 完整微信小程序授权登录页面教程

    完整微信小程序授权登录页面教程 1.前言 微信官方对getUserInfo接口做了修改,授权窗口无法直接弹出,而取而代之是需要创建一个button,将其open-type属性绑定getUseInfo方 ...

  3. 解决微信公众号授权登录和开放平台微信第三方应用授权登录获取到的用户Openid关联问题

    开发背景: 最近一段时间一直在做关于微信方面的网站应用开发,这段时间也收获的不少关于微信开发方面的开发技能,接触的比较多的主要有微信公众号和微信网站app第三方登录授权,以及微信会员卡,优惠券和扫描二 ...

  4. 微信公众平台网页登录授权多次重定向跳转,导致code使用多次问题

    背景:微信网站开发 昨天我负责的一个项目忽然出现了一个十分诡异的bug,进行微信授权登录的时候请求code的时候安卓手机会多次重定向调转我的接口接收code的接口(redirect_uri 微信请求调 ...

  5. 微信小程序授权登录将open_id传至后台并入库

    要求能把用户昵称.头像以及open_id写入数据库,服务端保持用户登录状态 wxml: <block wx:else> <button type="primary" ...

  6. 微信公众号授权登录后报redirect_uri参数错误的问题

      在进行微信公众号二次开发的时候,需要通过授权码模式来进行微信授权.比如,在进行登录的时候,用户点击了登录按钮,然后弹出一个授权框,用户点击同意后,就可以获取用户的OpenId等信息了.这篇文章主要 ...

  7. 微信小程序授权登录

    目录 自定义授权页面 点击授权登录后出现微信自带的授权登录弹窗 <!--index.wxml--> <!-- 授权界面 --> <cover-view class='au ...

  8. 微信公众号授权登录,提示“redirect_uri 参数错误”

    做微信公众号开发授权登录的时候遇到的坑... 后台服务用node,index.js相关代码如下: const oauth = new OAuth(conf.appid, conf.appsecret) ...

  9. uni-app开发经验分享二十: 微信小程序 授权登录 获取详细信息 获取手机号

    授权页面 因为微信小程序提供的 权限弹窗 只能通用户确认授权 所以可以 写一个授权页面,让用户点击 来获取用户相关信息 然后再配合后台就可以完成登录 <button class="bt ...

  10. 微信小程序授权登录以及用户信息相关接口调整导致授权框不弹出

    前言:4月8号升级了小程序业务后提交了版本并上线.突然一个同事说体验版的点击"登录"按钮无效.当时觉得应该不会呀,这几天一直用手机调试,每天也在不停的登录授权,弹框一直有的呀.然后 ...

随机推荐

  1. python机器学习——随机森林算法

    背景与原理: 首先我们需要知道集成学习的概念,所谓集成学习,就是使用一系列学习器进行学习,并且通过某种规则把这些学习器的学习结果整合起来从而获得比单个学习器学习效果更好的机器学习方法.这样的方法可以用 ...

  2. Unity鼠标点选RenderTexture里渲染的3D模型

    公司的产品有个功能:在主相机之外,另有一个摄像机来渲染不同的3D模型,然后把摄像机的RenderTexture赋值给一个 rawImage.texture,作为2D的UGUI来显示.(应用场景:模型结 ...

  3. c++学习8 动态空间申请

    一 动态分配内存的概述 在数组一幕中,介绍过数组的长度是事先预定好的,在整个程序中固定不变.但是在实际的编程过程中,往往会发生这种情况:我们并不清楚到底需要多少数目的空间,而且无法事先预定,所以对了应 ...

  4. Java基础|03.基础语法(2)

    Java安全|03.Java基础语法(2) 00x1 单例模式 定义: 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一 ...

  5. oracle 存过调试 stepinto stepover stepout

    step into:单步执行,遇到子函数就进入并且继续单步执行(简而言之,进入子函数): step over:在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止, ...

  6. test image size

    676KB - jpg 2.5M jpg 3.8M-jpg 4M

  7. 将本地文件复制到docker 容器中

    查询容器id: docker ps 查询完整容器id docker inspect -f '{{.ID}}'短容器id cp docker cp 本地路径 完整容器ID:容器路径例: docker c ...

  8. 智利SUBTEL更新WiFi 6技术法规!

    2022年9月6日,智利电信监管机构(SUBTEL) 发布了第2844号豁免决议,更新了1985号豁免决议,即短程设备的固定技术标准. 主要更新如下: • 2.4 GHz频段已在医疗设备目录中删除,现 ...

  9. 通过Linux的socket套接字实现客户端与服务器端的通信

    具体案例:使用树莓派ds18b20温度传感器实现温度上报 首先需要获得传感器文件中保存的温度信息: 温度信息通常保存在路径为"/sys/bus/w1/devices/28-xxxxxxxxx ...

  10. 1、Java程序概述

    1.什么是Java? Java是一个完整的平台,有一个庞大的库,其中包含了很多可重用的代码,以及一个提供诸如安全性.跨操作系统的可移植性以及自动垃圾收集等服务的执行环境. 2.Java白皮书的关键术语 ...