目录
1.代开发应用模板创建与配置
1.1创建代开发应用模板
1.2模板配置开发信息
1.3模板回调处理微信后台通知事件
1.4应用回调URL配置
1.5获取代开发应用secret(permanent_code)
2.代开发应用上线
3.代开发应用获取企业微信用户信息
1.代开发应用模板创建与配置
1.1创建代开发应用模板
1.2模板配置开发信息
1.服务商代开发模板回调URL
说明:后续企业微信后台部分通知会推送到此回调URL
注意:这里配置时会要求验证代开发模板回调URL,这里可以使用官方的加解密库进行验证
服务端加解密方案说明:https://developer.work.weixin.qq.com/devtool/introduce?id=36388
官方加解密库示例下载:https://developer.work.weixin.qq.com/devtool/introduce?id=10128
- 这里以php版本为例
1.目录结构
2.验证url正确性需要参数
encodingAesKey //模板配置开发信息中的EncodingAesKey
Token //模板配置开发信息中的Token
corpId //服务商id 企业服务商后台通用开发参数里
文件:Sample.php
/*
------------使用示例一:验证回调URL---------------
*企业开启回调模式时,企业号会向验证url发送一个get请求
假设点击验证时,企业收到类似请求:
* GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3×tamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D
* HTTP/1.1 Host: qy.weixin.qq.com接收到该请求时,企业应
1.解析出Get请求的参数,包括消息体签名(msg_signature),时间戳(timestamp),随机数字串(nonce)以及公众平台推送过来的随机加密字符串(echostr),
这一步注意作URL解码。
2.验证消息体签名的正确性
3. 解密出echostr原文,将原文当作Get请求的response,返回给公众平台
第2,3步可以用公众平台提供的库函数VerifyURL来实现。*/$encodingAesKey = 'In9LJMuhLVN6x5Qkg8Kx3DmHV3xdKnxlJrKJnYt8lxF';
$token = 'aMRVjNDZ';
$corpId = '';//服务商id$sVerifyMsgSig = $_GET['msg_signature'];
$sVerifyTimeStamp = $_GET['timestamp'];
$sVerifyNonce = $_GET['nonce'];
$sVerifyEchoStr = $_GET['echostr'];if (isset($sVerifyEchoStr)) {
//这里记录获取到的参数,以便调试$myfile = fopen("log.txt", "w") or die("Unable to open file!");fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sVerifyMsgSig: " . $sVerifyMsgSig . "\r\n");fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sVerifyTimeStamp: " . $sVerifyTimeStamp . "\r\n");fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sVerifyNonce: " . $sVerifyNonce . "\r\n");fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sVerifyEchoStr: " . $sVerifyEchoStr . "\r\n");// 需要返回的明文$sEchoStr = "123456";$wxcpt = new WXBizMsgCrypt($token, $encodingAesKey, $corpId);$errCode = $wxcpt->VerifyURL($sVerifyMsgSig, $sVerifyTimeStamp, $sVerifyNonce, $sVerifyEchoStr, $sEchoStr);if ($errCode == 0) {echo $sEchoStr;// 验证URL成功,将sEchoStr返回// HttpUtils.SetResponce($sEchoStr);} else {print("ERR: " . $errCode . "\n\n");//fwrite($myfile, "" . date('Y-m-d H:i:s') . "----errCode: " . $errCode . "\r\n");}fclose($myfile);
}
到这里,模板配置成功.
1.3模板回调处理微信后台通知事件
回调接口官方概述:https://developer.work.weixin.qq.com/document/path/90613
目前常用到的通知事件有
请求的包体中InfoType代表通知事件类型
1.推送suite_ticket:https://developer.work.weixin.qq.com/document/path/90628
2.授权成功通知事件:https://developer.work.weixin.qq.com/document/path/90642
这个里面拿到的auth_code可以获取到应用secret,secret用于获取应用access_token,该access_token用于获取用户敏感信息
3.重置永久授权码通知事件:https://developer.work.weixin.qq.com/document/path/94758
这个里面拿到的auth_code可以获取到应用secret,secret用于获取应用access_token,该access_token用于获取用户敏感信息
注意:
1.下面这个处理逻辑仍然是在模板回调url指向的文件里,前面url正确性验证通过后需要注释掉验证url正确性相关逻辑代码,不然会出错。
2.通知收到以后,必须立即作出响应,文档里的通知事件响应是返回一个success字符串
文件:Sample.php
1.处理事件需要参数
encodingAesKey //模板配置开发信息中的EncodingAesKey
Token //模板配置开发信息中的Token
corpId // 这里用的是刚刚创建成功的模板id
$encodingAesKey = '';
$token = '';
$corpId = ''; //模板id$cn = new CommonFunc(); //公共函数类
$sReqMsgSig = $_GET["msg_signature"];
$sReqTimeStamp = $_GET["timestamp"];
$sReqNonce = $_GET['nonce'];
// 获取post请求的密文数据
$sReqData = file_get_contents("php://input");
$sMsg = ""; // 解析之后的明文
$wxcpt = new WXBizMsgCrypt($token, $encodingAesKey, $corpId);
$errCode = $wxcpt->DecryptMsg($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $sReqData, $sMsg);
$myfile = fopen("log.txt", "w") or die("Unable to open file!");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----msg_signature: " . $sReqMsgSig . "\r\n");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----timestamp: " . $sReqTimeStamp . "\r\n");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----nonce: " . $sReqNonce . "\r\n");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sReqDatas: " . $sReqData . "\r\n");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sMsg: " . $sMsg . "\r\n");
if ($errCode == 0) {// 解密成功,sMsg即为xml格式的明文//var_dump($sMsg);echo 'success'; //响应企业微信的请求// TODO: 对明文的处理/*"<xml><SuiteId><![CDATA[dk623666a23e0de46f]]></SuiteId><AuthCode><![CDATA[uRRKjj2uhp5nLyTHb-s-32ddSru9zK-6Jy3hmuOTQFPWj-dseQ2L9bGXyfbEaWYa4jU43C5AmWl_bbGoAbfL9rKcZgqUrH_xIKtAds0Z1oc]]></AuthCode><InfoType><![CDATA[reset_permanent_code]]></InfoType><TimeStamp>1661756691</TimeStamp></xml>"
*///解析xml数据$arr = (array)simplexml_load_string($sMsg, 'SimpleXMLElement', LIBXML_NOCDATA);$InfoType = $arr['InfoType'];if ($InfoType == 'reset_permanent_code') {//重置授权码通知事件fwrite($myfile, "" . date('Y-m-d H:i:s') . "----AuthCode: " . $arr['AuthCode'] . "\r\n");$auth_code_file = fopen("auth_code.txt", "w");fwrite($auth_code_file, $arr['AuthCode']);fclose($auth_code_file);//保存授权应用密钥$cn->getSecret();} else if ($InfoType == 'suite_ticket') {//推送suite_ticket通知事件fwrite($myfile, "" . date('Y-m-d H:i:s') . "----SuiteTicket: " . $arr['SuiteTicket'] . "\r\n");$suite_ticket_file = fopen("suite_ticket.txt", "w");fwrite($suite_ticket_file, $arr['SuiteTicket']);fclose($suite_ticket_file);} else if ($InfoType == 'create_auth') {//授权成功通知通知事件fwrite($myfile, "" . date('Y-m-d H:i:s') . "----AuthCode: " . $arr['AuthCode'] . "\r\n");$auth_code_file = fopen("auth_code.txt", "w");fwrite($auth_code_file, $arr['AuthCode']);fclose($auth_code_file);//保存授权应用密钥$cn->getSecret();}
} else {fwrite($myfile, "" . date('Y-m-d H:i:s') . "----errCode: " . $errCode . "\r\n");//exit(-1);
}
fclose($myfile);
公共函数类
class CommonFunc
{/*** 获取应用授权的token(suite_access_token)* 获取步骤 * 1.通过suite_id(第三方应用ID),suite_secret(第三方应用密钥),suite_ticket(推送suite_ticket通知事件)换取suite_access_token*/public function getSuitAccessToken(){$suite_ticket_arr = file("suite_ticket.txt");$suite_ticket = $suite_ticket_arr[0];$suite_id = '';$suite_secret = '';//获取文件缓存中的suit_access_token$suite_access_token_arr = file("suite_access_token.txt");$suite_access_token = $suite_access_token_arr[0];$last_time = strtotime($suite_access_token_arr[1]);$now_time = time();$save_time = $now_time + 1.5 * 60 * 60;//一个半小时获取一次if ($last_time - $now_time < 1800) {$url = 'https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token';$post_data = array('suite_id' => $suite_id,'suite_secret' => $suite_secret,'suite_ticket' => $suite_ticket);$header = array('Content-type' => '');$result = $this->curl_post($url, $post_data, 5, $header, 'json');$suite_access_token_file = fopen("suite_access_token.txt", "w");fwrite($suite_access_token_file, $result['suite_access_token'] . "\r\n");fwrite($suite_access_token_file, date('Y-m-d H:i:s', $save_time) . "\r\n");fclose($suite_access_token_file);}return $suite_access_token;}/*** 获取代开发应用secret* 获取步骤 * 1.通过重置授权码通知事件获取auth_code(需要在服务商后台重置secret进行触发)* 2. 获取应用授权的token(suite_access_token)* 3.根据1,2步骤获取的参数去得到secret*/public function getSecret(){$auth_code_arr = file("auth_code.txt");$auth_code = $this->ClearHtml($auth_code_arr[0]);$suite_access_token = $this->ClearHtml($this->getSuitAccessToken());$url = 'https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=' . $suite_access_token;$post_data = array('auth_code' => $auth_code,);$header = array('Content-type' => '');//file_get_contents进行post请求,这里使用curl,报错提示网址错误,原因未知$res =$this->file_post($url, $post_data, 5, $header, 'json');$result = json_decode($res,true);$myfile = fopen("log.txt", "w");fwrite($myfile, $res);fclose($myfile);$secret = $result['permanent_code'];$secret_file = fopen("secret.txt", "w");fwrite($secret_file, $secret);fclose($secret_file);}/*** * curl post请求* */public function curl_post($url, $post_data = array(), $timeout = 5, $header = "", $data_type = ""){$header = empty($header) ? '' : $header;//支持json数据数据提交if ($data_type == 'json') {$post_string = json_encode($post_data);} elseif ($data_type == 'array') {$post_string = $post_data;} elseif (is_array($post_data)) {$post_string = http_build_query($post_data, '', '&');}$ch = curl_init(); // 启动一个CURL会话curl_setopt($ch, CURLOPT_URL, $url); // 要访问的地址curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查 // https请求 不验证证书和hostscurl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的Post请求curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string); // Post提交的数据包curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置超时限制防止死循环curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回 curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头$result = curl_exec($ch);if (curl_errno($ch)) {$curl_log = fopen("curl_log.txt", "w");fwrite($curl_log, date('Y-m-d H:i:s') . '--curl请求错误网址:' . $url . "\r\n");fwrite($curl_log, date('Y-m-d H:i:s') . '--curl请求错误' . curl_errno($ch) . "\r\n");fclose($curl_log);}$result = json_decode($result, true);curl_close($ch);return $result;}/*** file_get_contents进行post请求*/public function file_post($url, $post_data, $timeout = 5, $header = "", $data_type = ""){$postdata = json_encode($post_data);$options = array('http' => array('method' => 'POST','header' => 'Content-type:application/x-www-form-urlencoded','content' => $postdata,'timeout' => 15 * 60 // 超时时间(单位:s)));$context = stream_context_create($options);$result = file_get_contents($url, false, $context);return $result;}public function ClearHtml($str){$str = trim($str); //清除字符串两边的空格$str = strip_tags($str, ""); //利用php自带的函数清除html格式$str = preg_replace("/\t/", "", $str); //使用正则表达式替换内容,如:空格,换行,并将替换为空。$str = preg_replace("/\r\n/", "", $str);$str = preg_replace("/\r/", "", $str);$str = preg_replace("/\n/", "", $str);$str = preg_replace("/ /", "", $str);$str = preg_replace("/ /", "", $str); //匹配html中的空格return trim($str); //返回字符串}
}
到这里模板回调url配置完成。
1.4应用回调URL配置
这里暂时用已配置好的代开发应用配置示例
注意:这里Token和EncodingAESKey最好和模板配置开发时的保持一致
文件:CorpSample.php
验证URL回调
注意,应用的验证URL回调与模板的验证URL回调有点不一样这里不是直接用服务商id
这里企业主体的corpid需要转换为服务商的密文corpid
corpid转换:代开发应用安全性升级 - 接口文档 - 企业微信开发者中心
获取服务商凭证:https://developer.work.weixin.qq.com/document/path/91200
所需要的参数
$encodingAesKey = ''; //配置的encodingAesKey
$token = '';//配置的token
$corpId = ''; //企业号id 登录企业微信后台,我的企业即可看到//服务商通用开发参数
$sCorpid = '';
$sProviderSecret = '';
逻辑代码
$encodingAesKey = 'In9LJMuhLVN6x5Qkg8Kx3DmHV3xdKnxlJrKJnYt8lxF';
$token = 'aMRVjNDZ';
$corpId = ''; //企业号id//服务商通用开发参数
$sCorpid = '';
$sProviderSecret = '';
$cn = new CommonFunc();
//获取服务商凭证
$sProviderToken = $cn->getProviderToken($sCorpid, $sProviderSecret);
$provider_access_token = $sProviderToken['provider_access_token'];
//获取转化呢后的密文corpid
$open_corpid_data = $cn->corpidChange($corpId, $provider_access_token);
$open_corpid = $open_corpid_data['open_corpid'];
$sVerifyMsgSig = $_GET['msg_signature'];
$sVerifyTimeStamp = $_GET['timestamp'];
$sVerifyNonce = $_GET['nonce'];
$sVerifyEchoStr = $_GET['echostr'];$myfile = fopen("log.txt", "w") or die("Unable to open file!");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sVerifyMsgSig: " . $sVerifyMsgSig . "\r\n");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sVerifyTimeStamp: " . $sVerifyTimeStamp . "\r\n");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sVerifyNonce: " . $sVerifyNonce . "\r\n");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----sVerifyEchoStr: " . $sVerifyEchoStr . "\r\n");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----provider_access_token: " . $provider_access_token . "\r\n");
fwrite($myfile, "" . date('Y-m-d H:i:s') . "----open_corpid: " . $open_corpid . "\r\n");
// 需要返回的明文
$sEchoStr = "123456";
$wxcpt = new WXBizMsgCrypt($token, $encodingAesKey, $open_corpid);
$errCode = $wxcpt->VerifyURL($sVerifyMsgSig, $sVerifyTimeStamp, $sVerifyNonce, $sVerifyEchoStr, $sEchoStr);
if ($errCode == 0) {echo $sEchoStr;// 验证URL成功,将sEchoStr返回// HttpUtils.SetResponce($sEchoStr);
} else {fwrite($myfile, "" . date('Y-m-d H:i:s') . "----errCode: " . $errCode . "\r\n");
}
fclose($myfile);class CommonFunc
{/*** 获取服务商的token* @param string $sCorpId 服务商管理后台通用开发参数-corpid* @param string $sProviderSecret 服务商管理后台通用开发参数-ProviderSecret*/public function getProviderToken($sCorpid, $sProviderSecret){$url = 'https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token';$res = $this->curl_post($url, array('corpid' => $sCorpid, 'provider_secret' => $sProviderSecret), 5, array('Content-type' => ''), 'json');return $res;}/*** * corpid转化* @param string $sCorpid 企业明文corpid* @param string $sToken 服务商token */public function corpidChange($sCorpId, $sToken){$url = 'https://qyapi.weixin.qq.com/cgi-bin/service/corpid_to_opencorpid?provider_access_token=' . $sToken;$res = $this->curl_post($url, array('corpid' => $sCorpId), 5, array('Content-type' => ''), 'json');return $res;}/*** * curl post请求* */public function curl_post($url, $post_data = array(), $timeout = 5, $header = "", $data_type = ""){$header = empty($header) ? '' : $header;//支持json数据数据提交if ($data_type == 'json') {$post_string = json_encode($post_data);} elseif ($data_type == 'array') {$post_string = $post_data;} elseif (is_array($post_data)) {$post_string = http_build_query($post_data, '', '&');}$ch = curl_init();//启动一个CURL会话curl_setopt($ch, CURLOPT_URL, $url); // 要访问的地址curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //对认证证书来源的检查https请求 不验证证书和hostscurl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//从证书中检查SSL加密算法是否存在curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);//模拟用户使用的浏览器curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的Post请求curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string); // Post提交的数据包curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);// 设置超时限制防止死循环curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回 curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头$result = curl_exec($ch);$result = json_decode($result, true);curl_close($ch);return $result;}
至此,应用回调url配置成功
1.5获取代开发应用secret(permanent_code)
1.通过suite_id(模板ID),suite_secret(模板Secret),suite_ticket(推送suite_ticket通知事件)换取suite_access_token
参考:https://developer.work.weixin.qq.com/document/path/90600
2.通过前面的授权成功通知事件或者重置永久授权码通知事件拿到的auth_code,
3.根据1,2步骤获取的参数去得到secret(获取企业永久授权码)
参考:https://developer.work.weixin.qq.com/document/path/90603
2.代开发应用上线
3.代开发应用获取企业微信用户信息
注意:这里需要授权企业登录企业微信后台对用户信息进行授权
这部分参考的是企业微信的自建应用开发,不是第三方应用开发
需要参数
'permanent_code'=>'',//代开发应用secret(永久授权码)'corpid'=>'',//企业明文CorpID'redirect_url'=>'',//授权重定向地址 'agentid'=>'1000006',//应用id
1.通过OAuth2的授权登录,前端获取到code,
- 参考:https://developer.work.weixin.qq.com/document/path/91119
- 2.后端通过前端提交的code,去获取access_token
- 这里面的corpsecret是前面获取的企业永久授权码 corpid就是企业明文id
- 参考:https://developer.work.weixin.qq.com/document/path/91039
- 3.获取访问用户身份
- 这里会获取到用户的USERID,scope为snsapi_privateinfo,且用户在应用可见范围之内时返回user_ticket,
- 后续利用该参数可以获取用户信息或敏感信息
- 参考:https://developer.work.weixin.qq.com/document/path/91023
- 4.获取用户详情
- 这里获取的是用户的基本信息,不包括敏感信息
- 参考:https://developer.work.weixin.qq.com/document/path/90196
- 5.获取用户敏感信息
- 参考https://developer.work.weixin.qq.com/document/path/95833
这里有个坑:使用开发者工具调试时,只能获取一次敏感信息,后续就不能,后来研究发现应该是微信开发者工具还未优化好这一部分,在真机上测试是正常的。开发者工具版本:1.06.2208010