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;
}
}
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微信三方平台-授权登录的更多相关文章
- 【tp5.1】微信公众号授权登录及获取信息录入数据库
微信公众号开发文档链接:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432 微信公众号授权登录分为两种: 1.以 ...
- 完整微信小程序授权登录页面教程
完整微信小程序授权登录页面教程 1.前言 微信官方对getUserInfo接口做了修改,授权窗口无法直接弹出,而取而代之是需要创建一个button,将其open-type属性绑定getUseInfo方 ...
- 解决微信公众号授权登录和开放平台微信第三方应用授权登录获取到的用户Openid关联问题
开发背景: 最近一段时间一直在做关于微信方面的网站应用开发,这段时间也收获的不少关于微信开发方面的开发技能,接触的比较多的主要有微信公众号和微信网站app第三方登录授权,以及微信会员卡,优惠券和扫描二 ...
- 微信公众平台网页登录授权多次重定向跳转,导致code使用多次问题
背景:微信网站开发 昨天我负责的一个项目忽然出现了一个十分诡异的bug,进行微信授权登录的时候请求code的时候安卓手机会多次重定向调转我的接口接收code的接口(redirect_uri 微信请求调 ...
- 微信小程序授权登录将open_id传至后台并入库
要求能把用户昵称.头像以及open_id写入数据库,服务端保持用户登录状态 wxml: <block wx:else> <button type="primary" ...
- 微信公众号授权登录后报redirect_uri参数错误的问题
在进行微信公众号二次开发的时候,需要通过授权码模式来进行微信授权.比如,在进行登录的时候,用户点击了登录按钮,然后弹出一个授权框,用户点击同意后,就可以获取用户的OpenId等信息了.这篇文章主要 ...
- 微信小程序授权登录
目录 自定义授权页面 点击授权登录后出现微信自带的授权登录弹窗 <!--index.wxml--> <!-- 授权界面 --> <cover-view class='au ...
- 微信公众号授权登录,提示“redirect_uri 参数错误”
做微信公众号开发授权登录的时候遇到的坑... 后台服务用node,index.js相关代码如下: const oauth = new OAuth(conf.appid, conf.appsecret) ...
- uni-app开发经验分享二十: 微信小程序 授权登录 获取详细信息 获取手机号
授权页面 因为微信小程序提供的 权限弹窗 只能通用户确认授权 所以可以 写一个授权页面,让用户点击 来获取用户相关信息 然后再配合后台就可以完成登录 <button class="bt ...
- 微信小程序授权登录以及用户信息相关接口调整导致授权框不弹出
前言:4月8号升级了小程序业务后提交了版本并上线.突然一个同事说体验版的点击"登录"按钮无效.当时觉得应该不会呀,这几天一直用手机调试,每天也在不停的登录授权,弹框一直有的呀.然后 ...
随机推荐
- 【LeetCode】 907 子数组的最小值之和
Decrisption Given an array of integers arr, find the sum of min(b), where b ranges over every (conti ...
- mybatis中xml配置文件头部
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC ...
- 微信小程序通过经纬度计算两点之间距离
小程序中通过经纬度计算两点之间的距离km 1.拾取两地经纬度坐标 . data:{ //当前定位位置 latitude: null, longitude: null, // 目的地坐标 latitud ...
- 新安装的eclipse没有新建java project----解决方法:安装插件
问题描述:最近新安装的一个eclipse版本,建立新工程的时候发现没有java project选项,如下: 百度了一些资料:https://blog.csdn.net/sinat_41752599/a ...
- CSS 层叠式-理解层叠性和继承性
CSS的概念中,除了前面提到的样式外,还有一个重要的概念就是层叠式,层叠式是贯穿整个css的一个性质,包含继承性和层叠性. 继承性: • 如果一个标签没有设置过一些样式,它的某个祖先级曾经设置过,在浏 ...
- Linux让部署在服务器上的项目一直保持运行状态…&跑多个项目
在idea通过package得到的.jar包或者.war包可通过 java -jar xxx.jar/xxx.war 命令直接在linux或者windows系统运行: 将打好包的项目放在linux ...
- requests模块获取cookie -----class 'requests.cookies.RequestsCookieJar'
#coding=utf-8 import requests url="http://www.baidu.com" response=requests.get(url) cookie ...
- HashMap记录
1.HashMap接收null的键值 2.HashMap是非synchronized的 3.HashMap使用hashCode找到bucket的位置.bucket中存储的是键和值 4.当HashCod ...
- java学习笔记(四)变量
局部变量,必须声明和初始化值: 实列变量,从属于对象:如果不自行初始化,这个类型的默认值,数值类型,0,0.0 布尔值 默认为false 除了基本类型下,其余的默认值都是null 如 变量类型 ...
- windows电脑设置【定时任务】开机、关机、启动程序
windows电脑设置[定时任务]开机.关机.启动程序 shutdown -s -t **(延时秒数):关机 shutdown -r -t **(延时秒数):重启 gina -s -t 36 (开机) ...