微信开放平台_第三方平台授权流程_验证票据
一、验证票据
1.1 官方说明:
验证票据(component_verify_ticket):在第三方平台创建审核通过后,微信服务器会向其“授权事件接收URL” 每隔 10 分钟以 POST 的方式推送 component_verify_ticket
接收 POST 请求后,只需直接返回字符串 success。为了加强安全性,postdata 中的 xml 将使用服务申请时的加解密 key 来进行加密,具体请见《加密解密技术方案》, 在收到推送后需进行解密(详细请见《消息加解密接入指引》)
作用:获取令牌时,需要使用票据值作为参数(component_verify_ticket)。
1.2 获取流程及示意代码
微信服务器会向其 ”授权事件接收URL” 每隔 10 分钟以 POST
的方式推送( component_verify_ticket)
授权事件接收URL:“在开放平台管理中心”中寻找,如下图。填写完整的URL请求路径。
(比如请求路径填写为:http://登录授权的发起页域名/项目名/api/wx/open/getComponentVerifyTicket)
获取票据(componentVerifyTicket),示意代码:
SpringMVC形式的Controller层:
/**
* 接收微信服务器发送的component_verify_ticket
*/
@PostMapping("/getComponentVerifyTicket")
public String getComponentVerifyTicket(HttpServletRequest request, HttpServletResponse response) throws Exception {
log.info("接收微信服务器发送的component_verify_ticket begin");
try {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
// 微信加密签名
String msg_signature = request.getParameter("msg_signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 从请求中读取整个post数据
InputStream inputStream;
String postData = null;
inputStream = request.getInputStream();
postData=IOUtils.toString(inputStream, "UTF-8"); //获取接收到消息里的XML密文,存放在postData中
log.info("postData:"+postData);
WXBizMsgCrypt wxcpt = null;
log.info("postData:"+postData);
log.info("msg_signature:"+msg_signature);
log.info("timestamp:"+timestamp);
log.info("nonce:"+nonce);
log.info("getServetoken:"+ComponentConfig.TOKEN); //token
log.info("getServeencodingaeskey:"+ComponentConfig.AESKEY); //aeskey
log.info("getServeappid:"+ComponentConfig.APPID); //appid
log.info("ip:"+ NetworkUtil.getIpAddress(request));
//从XML中获取<Encrypt></Encrypt>标签内的密文文本
String encrypt = XMLUtil2.getLabelFromXml(postData,"Encrypt");
log.info("Encrypt:"+encrypt);
//格式化密文文本,否则没有<ToUserName>标签,会解密失败,参考官方的加解密代码JAVA版本
String format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>";
String fromXML = String.format(format, encrypt);
String msg = ""; //解密后的明文
if(StringUtil.isEmpty(encrypt)) {
msg = fromXML;
} else {
wxcpt = new WXBizMsgCrypt(ComponentConfig.TOKEN,ComponentConfig.AESKEY,ComponentConfig.APPID);
// 解密消息
msg = wxcpt.decryptMsg(msg_signature, timestamp, nonce, fromXML);
}
log.info("msg:"+msg);
//将XML格式字符串转为Map类型
Map<String, String> msgMap = XMLUtil.xmlToMap(msg);
String infotype = msgMap.get("InfoType"); //获取infotype,注:微信开放平台文档中标明固定为:"component_verify_ticket",但参考其他代码,还包含authorized???
log.info(infotype);
switch (infotype){
case "component_verify_ticket": //验证票据
String ComponentVerifyTicket = msgMap.get("ComponentVerifyTicket");
webChatCatchUtil.setWeixinOpenComponentVerifyTicket(ComponentVerifyTicket); //将票据值写入Redis缓存中
log.info("component_verify_ticket:"+ComponentVerifyTicket);
break;
case "unauthorized"://用户取消授权
break;
}
} catch (Exception e) {
log.error("Exception",e);
}
return "success";
}
使用wxcpt.decryptMsg获取到的解密后的result示例:
<xml> |
注意:
component_verify_ticket 的有效时间较 component_access_token 更长,建议保存最近可用的component_verify_ticket,在 component_access_token 过期之前可以直接使用该 component_verify_ticket 进行更新,避免出现因为 component_verify_ticket 接收失败而无法更新 component_access_token 的情况。