分享一下微信的第三方平台授权吧,中间还是有挺多坑的,开发前一定要仔细的看几遍文档
一、首先在微信申请成为第三方,流程按着微信提示的走就好了
二、开发授权
1、接收 微信的推送 component_verify_ticket 协议
在第三方平台创建审核通过后,微信服务器会向其“授权事件接收URL”每隔10分钟定时推送component_verify_ticket。第三方平台方在收到ticket推送后也需进行解密(详细请见【消息加解密接入指引】),接收到后必须直接返回字符串success。
点进【消息加解密接入指引】后,下载SDK包,在项目中引入,我就用ThinkPHP5举例了
将php包放到 /extend/Wxapi/
<?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