前段时间做了一个微信第三方授权,一直想写一篇文章分享一下,但是总是忙,今天终于有空闲给写出来了,整个流程很简单清晰,在签名验证的地方可能有点儿小坑,并且在用户取消授权的时候,微信api说的是会把消息推送到回调地址中,在这里强调一下这个回调地址不是授权时候的回调地址,而是你申请第三方平台时候填写的授权地址,闲话少说进入正题。(如有问题,可留言交流)
简单流程先描述
用户点击授权按钮 -> 获取第三方令牌 -> 获取预授权码 -> 进入微信授权页面 -> 用户扫码授权 -> 微信推送授权结果
第一步 维护微信推送的 component_verify_ticket
在第三方平台创建审核通过后,微信服务器会向其“授权事件接收URL”每隔10分钟定时推送component_verify_ticket,该ticket是加密的xml串,需要解码获取到ticket值(用于获取预授权码);
解密用的是php的加解密模块(安装php自带的),代码用的是微信提供的。
代码如下
$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'); // xml
$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);
// 第三方收到公众号平台发送的消息
$weixinConfig = Config::get('weixin');
$appId = $weixinConfig['app_id'];
$appKey = $weixinConfig['app_key'];
$appToken = $weixinConfig['app_token'];
$msg = '';
$pc = new WXBizMsgCrypt( $appToken, $appKey, $appId );
$errCode = $pc->decryptMsg($msg_sign, $timeStamp, $nonce, $from_xml, $msg);
// 解密失败
if ( $errCode != 0 ) {
echo'error';
return;
}
$xml = new DOMDocument();
$xml->loadXML($msg);
$array_auth = $xml->getElementsByTagName('InfoType');
$infoType = $array_auth->item(0)->nodeValue;
$array_e = $xml->getElementsByTagName('ComponentVerifyTicket');
$ticket = $array_e->item(0)->nodeValue;
第二步 获取第三方平台component_access_token
第三方平台compoment_access_token是第三方平台的下文中接口的调用凭据,也叫做令牌(component_access_token)。每个令牌是存在有效期(2小时)的,且令牌的调用不是无限制的,请第三方平台做好令牌的管理,在令牌快过期时(比如1小时 50分)再进行刷新。 令牌的维护可以参考微信的中控,我的处理方式是通过微信给我推送component_verify_ticket的10分钟间隔来做的。
代码如下
$weixinConfig = Config::get('weixin');
$appId = $weixinConfig['app_id'];
$appSecret = $weixinConfig['app_secret'];
$postData = array(
'component_appid' => $appId,
'component_appsecret' => $appSecret,
'component_verify_ticket' => $verifyTicket
);
$postData = json_encode( $postData );
$result = $this->curl_post( 'https://api.weixin.qq.com/cgi-bin/component/api_component_token', $postData );
第三步 获取预授权码pre_auth_code
预授权码是每次要用的话通过access_token重新生成的,没有次数限制
代码如下
$weixinConfig = Config::get('weixin');
$appId = $weixinConfig['app_id'];
$postData = array(
'component_appid' => $appId
);
$postData = json_encode( $postData );
$result = $this->curl_post( 'https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token='.$accessToken, $postData );
第四步 进入微信授权页面
进入微信授权页面会出现一个二维码,用户通过扫码在手机端进行授权操作,这里需要注意的一个东西是,进入微信授权页面时候需要传入一个回调地址,该回调地址后边可以跟参数,这样你本地代码和微信授权服务就一条线连起来了
代码如下
$weixinConfig = Config::get('weixin');
$appId = $weixinConfig['app_id'];
$hostMaps = Config::get('hostMaps');
$wxAuthCallback = $hostMaps['wx_auth_callback'];
$hostMaps = Config::get('hostMaps');
$wxAuthRequest = $hostMaps['wx_auth_request'];
$html_text = $this->buildRequestForm( array(), "POST", $wxAuthRequest.'?component_appid='.$appId.'&pre_auth_code='.$preAuthCode.'&redirect_uri='.$wxAuthCallback.'?callback_param='.$callbackParams, true );
// 同步跳转方法(仿照支付宝)
protected function buildRequestForm( array $param, $method, $target='',$jump=false) {
$sHtml = "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' /><form id='autoSubmit' action='".$target."' method='".$method."'>";
if ( !empty( $param ) ) {
foreach( $param as $key => $value ) {
$sHtml.= "<input type='hidden' name='".$key."' value='".urldecode($value)."'/>";
}
}
$sHtml .= "</form>";
if($jump) $sHtml = $sHtml."<script>document.getElementById("autoSubmit").submit();</script>";
return $sHtml;
}
第五步 微信授权消息推送
用户授权之后微信接收到授权结果,然后把授权结果推送给你授权时候的回调地址,推送消息里边会有一个 auth_code,你需要通过auth_code获取授权方的access_token(接口调用凭证);
不同平台需求可能不一样,逻辑简单所以代码就不放了。
有一点需要注意的是调用凭证access_token有两个小时的有效期,并且access_token获取是有次数限制的,所以需要做好本地维护工作,切入点是获取access_token的时间,每次从数据库中获取access_token时可以先判定一下获取时间然后再决定
是直接用还是重新获取。
判定代码如下
strtotime("+ $verityAccessTime minutes", $createTime) < time()
微信第三方授权流程网址 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1453779503&token=&lang=zh_CN
本文为原创,创作不易,如要转载请注明本文出处;
多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查询结果会被放到一个缓存中,这样,后续的相同的查询就不用操作表而直