授權流程
1. 接收component_verify_ticket:
[1]微信服務器每隔10分鐘會向第三方的消息接收地址推送一次component_verify_ticket,拿到後需要在本地做好存儲;
[2]微信第三方平臺的消息是加密的(下圖),需要進行解密才能獲取需要的信息;
[3]接收並解密消息,代碼如下:
/**
* 授權事件接收URL
*/
public function msg() {
import("@.ORG.ArrayTool");
import("@.ORG.Weixincrypt.WXBizMsgCrypt");
$timestamp = empty($_GET ['timestamp']) ? '' : trim($_GET ['timestamp']);
$nonce = empty($_GET ['nonce']) ? '' : trim($_GET ['nonce']);
$msgSign = empty($_GET ['msg_signature']) ? '' : trim($_GET ['msg_signature']);
$signature = empty($_GET ['signature']) ? '' : trim($_GET ['signature']);
$encryptType = empty($_GET ['encrypt_type']) ? '' : trim($_GET ['encrypt_type']);
$encryptMsg = file_get_contents('php://input');
$wxData = C("platform_setting");
$encodingAesKey = $wxData['encodingAesKey'];
$token = $wxData['token'];
$appId = $wxData['appId'];
$Wxcrypt = new WXBizMsgCrypt($token, $encodingAesKey, $appId);
$postArr = ArrayTool::xml2array($encryptMsg);
$format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%s]]></Encrypt></xml>";
$fromXml = sprintf($format, $postArr['Encrypt']);
//第三方收到公衆號平臺發送的消息
$msg = '';
$errCode = $Wxcrypt->decryptMsg($msgSign, $timestamp, $nonce, $fromXml, $msg); // 解密
if ($errCode == 0) {
$param = ArrayTool::xml2array($msg);
switch ($param['InfoType']) {
case 'component_verify_ticket' : // 授權憑證
$componentVerifyTicket = $param['ComponentVerifyTicket'];
S('component_verify_ticket_' . $appId, $componentVerifyTicket);
break;
case 'unauthorized' : // 取消授權
break;
case 'authorized' : // 授權
break;
case 'updateauthorized' : // 更新授權
break;
}
}
exit("success");
}
2.獲取component_access_token:
[1]每個令牌是存在有效期(2小時)的,且令牌的調用不是無限制的,請第三方平臺做好令牌的管理,在令牌快過期時(比如1小時50分)再進行刷新。所以要對component_access_token做好本地緩存,代碼如下:
$wxData = C("setting");
//1. 取得component_verify_ticket
$vt = S('component_verify_ticket_' . $wxData['appId']);
$at = S('component_access_token_' . $wxData['appId']);
//2. 獲取第三方平臺component_access_token
if (empty($at) && !empty($vt)) {
$url2 = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";
$post = array();
$post['component_appid'] = $wxData['appId'];
$post['component_appsecret'] = $wxData['appSecret'];
$post['component_verify_ticket'] = $vt;
$return2 = $this->curlPost($url2, $post);
if (isset($return2['component_access_token'])) {
$at = $return2['component_access_token'];
S('component_access_token_' . $wxData['appId'], $at, 6600); //緩存1小時50分鐘 = 6600秒
} else {
return false;
}
}
3.獲取pre_auth_code(注意這是預授權碼,不是授權碼):
$wxData = C('platform_setting');
$appId = $wxData['appId'];
$HT = new HttpTool();
$at = $HT->getComponentAccessToken();
if ($at) {
//3.獲取預授權碼pre_auth_code
$url3 = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token={$at}";
$post = array();
$post['component_appid'] = $appId;
$return3 = $HT->curlPost($url3, $post);
if (isset($return3['pre_auth_code'])) {
$preauthcode = $return3['pre_auth_code'];
$redirectUrl = C('site_url') . U("User/App/setauth", array('uid' => $uid));
$weixinUrl = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid={$appId}&pre_auth_code={$preauthcode}&redirect_uri={$redirectUrl}";
redirect($weixinUrl);
exit;
}
}
$this->error("親, 授權失敗了!");
4.使用授權碼換取公衆號的接口調用憑據和授權信息:
//1. 使用授權碼換取公衆號的接口調用憑據和授權信息
import("@.ORG.HttpTool");
$HT = new HttpTool();
$wxData = C('platform_setting');
$caccessToken = $HT->getComponentAccessToken();
$url1 = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token={$caccessToken}";
$post = array();
$post['component_appid'] = $wxData['appId'];
$post['authorization_code'] = $authcode;
$return = $HT->curlPost($url1, $post);
if (isset($return['authorization_info'])) {
$authinfo = $return['authorization_info'];
$authid = $authinfo['authorizer_appid'];
$accessToken = $authinfo['authorizer_access_token'];
$refreshToken = $authinfo['authorizer_refresh_token'];
//$funcInfo = $authinfo['func_info'];
//2. 獲取授權方的公衆號帳號基本信息
$url2 = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token={$caccessToken}";
$post = array();
$post['component_appid'] = $wxData['appId'];
$post['authorizer_appid'] = $authid;
$return2 = $HT->curlPost($url2, $post);
if (isset($return2['authorizer_info'])) {
$wxinfo = $return2['authorizer_info'];
$fcinfo = $return2['authorization_info'];
$Wxuser = M("Wxuser");
//是否已經存在
$extFilter = array();
$wxuser['uid'] = $uid;
$extFilter['auth_appid'] = $fcinfo['authorizer_appid'];
$isExt = $Wxuser->where($extFilter)->find();
$wxuser = array();
$wxuser['uid'] = $uid;
$wxuser['token'] = $this->getToken();
$wxuser['wxid'] = $wxinfo['user_name']; //原始ID
$wxuser['wxname'] = $wxinfo['nick_name']; //暱稱
$wxuser['weixin_type'] = $wxinfo['service_type_info']['id']; //微信類型 授權方公衆號類型,0代表訂閱號,1代表由歷史老帳號升級後的訂閱號,2代表服務號
$wxuser['weixin'] = $wxinfo['alias']; //微信號
$wxuser['headerpic'] = $wxinfo['head_img']; //頭像
$wxuser['bind_type'] = 1;
$wxuser['auth_appid'] = $fcinfo['authorizer_appid'];
$wxuser['auth_access_token'] = $accessToken;
$wxuser['auth_refresh_token'] = $refreshToken;
$wxuser['auth_functions'] = json_encode($fcinfo['func_info']);
$wxuser['auth_business_info'] = json_encode($wxinfo['business_info']);
$wxuser['create_time'] = time();
if ($isExt) {
$sign = $Wxuser->where($extFilter)->save($wxuser);
} else {
$sign = $Wxuser->add($wxuser);
if ($sign) {
//添加功能模塊
$this->addfc($wxuser['token']);
//記錄公衆號數量
M('Users')->where(array('id' => $uid))->setInc('wechat_card_num');
}
}
if ($sign) {
redirect(C("site_url") . U('User/Index/index'));
}
}
}
$this->error("親,獲取授權信息失敗!", U('User/Index/index'));
二. 全網發佈
代碼如下:
/**
* 公衆號消息與事件接收URL
*/
public function index() {
$timestamp = empty($_GET['timestamp']) ? '' : trim($_GET['timestamp']);
$nonce = empty($_GET['nonce']) ? '' : trim($_GET ['nonce']);
$msgSign = empty($_GET['msg_signature']) ? '' : trim($_GET['msg_signature']);
$signature = empty($_GET['signature']) ? '' : trim($_GET['signature']);
$encryptType = empty($_GET['encrypt_type']) ? '' : trim($_GET['encrypt_type']);
$openid = trim($_GET['openid']);
import("@.ORG.ArrayUtil");
import("@.ORG.Weixincrypt.WXBizMsgCrypt");
$input = file_get_contents('php://input');
$paramArr = ArrayUtil::xml2array($input);
//$this->logPrint($paramArr);
//$this->logPrint($_GET);
//解密
$wxData = C("platform_setting");
$encodingAesKey = $wxData['encodingAesKey'];
$token = $wxData['token'];
$appId = $wxData['appId'];
$Wxcrypt = new WXBizMsgCrypt($token, $encodingAesKey, $appId);
$format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%s]]></Encrypt></xml>";
$fromXml = sprintf($format, $paramArr['Encrypt']);
$errCode = $Wxcrypt->decryptMsg($msgSign, $timestamp, $nonce, $fromXml, $toXml); // 解密
$this->logPrint($toXml);
if ($errCode == 0) {
$param = ArrayUtil::xml2array($toXml);
$keyword = isset($param['Content']) ? trim($param['Content']) : '';
// 案例1 - 發送事件
if (isset($param['Event']) && $paramArr['ToUserName'] == 'gh_3c884a361561') {
$contentStr = $param ['Event'] . 'from_callback';
}
// 案例2 - 返回普通文本
elseif ($keyword == "TESTCOMPONENT_MSG_TYPE_TEXT") {
$contentStr = "TESTCOMPONENT_MSG_TYPE_TEXT_callback";
}
// 案例3 - 返回Api文本信息
elseif (strpos($keyword, "QUERY_AUTH_CODE:") !== false) {
import("@.ORG.HttpTool");
$authcode = str_replace("QUERY_AUTH_CODE:", "", $keyword);
$contentStr = $authcode . "_from_api";
$HT = new HttpTool();
$authDetail = $HT->getAccessTokenByAuthCode($authcode);
$accessToken = $authDetail['authorizer_access_token'];
$HT->sendFansText($accessToken, $param['FromUserName'], $contentStr);
//$tokenInfo = WechatOpenApiLogic::getAuthorizerAccessTokenByAuthCode($ticket);
//$param ['authorizerAccessToken'] = $tokenInfo ['authorization_info'] ['authorizer_access_token'];
//self::sendServiceMsg($param['FromUserName'], $param['ToUserName'], 1, $contentStr); // 客服消息接口
return 1;
}
$result = '';
if (!empty($contentStr)) {
$xmlTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$result = sprintf($xmlTpl, $param['FromUserName'], $param['ToUserName'], time(), $contentStr);
if (isset($_GET['encrypt_type']) && $_GET['encrypt_type'] == 'aes') { // 密文傳輸
$wxData = C("platform_setting");
$msgCryptObj = new WXBizMsgCrypt($wxData['token'], $wxData['encodingAesKey'], $wxData['appId']);
$encryptMsg = '';
$msgCryptObj->encryptMsg($result, $_GET['timestamp'], $_GET['nonce'], $encryptMsg);
$result = $encryptMsg;
}
}
echo $result;
}
}