在第三方平臺創建審覈通過後,微信服務器會向其“授權事件接收URL”每隔10分鐘定時推送component_verify_ticket。第三方平臺方在收到ticket推送後也需進行解密(詳細請見【消息加解密接入指引】),接收到後必須直接返回字符串success。
1. 獲取component_verify_ticket接口配置
接口名要與微信開發平臺第三方平臺上配置的"授權事件接收URL"接口名對應。
例:getComponentVerifyTicket
2. 寫接口
/**
* 接收component_verify_ticket 或 authorized事件
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@ApiOperation(value = "接收component_verify_ticket 或 authorized事件", notes = "接收component_verify_ticket 或 authorized事件", response = String.class)
@RequestMapping(value = "getComponentVerifyTicket")
public void getComponentVerifyTicket(HttpServletRequest request, HttpServletResponse response) throws Exception {
logger.info("接收component_verify_ticket 或 authorized事件");
String nonce = request.getParameter("nonce");
String timestamp = request.getParameter("timestamp");
String msgSignature = request.getParameter("msg_signature");
StringBuilder sb = new StringBuilder();
BufferedReader in = request.getReader();
String line;
while((line = in.readLine()) != null) {
sb.append(line);
}
String postData = sb.toString();
logger.info("nonce: " + nonce);
logger.info("timestamp: " + timestamp);
logger.info("msgSignature: " + msgSignature);
logger.info("postData: " + postData);
thirdPartyService.getComponentVerifyTicket(timestamp, nonce, msgSignature, postData);
responseUtil(response, "success");
// return "success";
}
@Override
public void getComponentVerifyTicket(String timestamp, String nonce, String msgSignature, String postData) throws Exception {
// 需要加密的明文
WXBizMsgCrypt pc = new WXBizMsgCrypt(TOKEN, ENCODING_AES_KEY, THIRD_PARTY_APP_ID);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(postData);
InputSource is = new InputSource(sr);
Document document = db.parse(is);
Element root = document.getDocumentElement();
NodeList nodelist1 = root.getElementsByTagName("Encrypt");
String encrypt = nodelist1.item(0).getTextContent();
String format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>";
String fromXML = String.format(format, encrypt);
String result = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);
logger.info("解密後: " + result);
//獲取ComponentVerifyTicket
Map<String, String> xmlMap = xmlToMap(result);
String componentVerifyTicket = xmlMap.get("ComponentVerifyTicket");
if(StringUtils.isNotBlank(componentVerifyTicket)) {
//獲取ticket,沒有則爲authorized事件
RedisUtils.set("ComponentVerifyTicket", componentVerifyTicket);
logger.info("ComponentVerifyTicket: " + componentVerifyTicket);
}
}
3. 坑
a. 需要注意的是這個接口會有兩種數據形式訪問,一個是component_verify_ticket,解密後有ComponentVerifyTicket這個參數,另一個是authorized事件,解密後沒有ComponentVerifyTicket這個參數,因此在獲取componentVerifyTicket時要加個判斷。
b. 同時需要注意的是,解密時要加上<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>
原因是官方的demo文件裏,類XMLParse.java裏,提取出xml數據包中的加密消息這個方法(extract(String xmltext))有一步需要獲取字段ToUserName,
而原數據沒有這個字段,所以或報異常。
c. 在全網發佈檢測時“組件ticket正確接收”一直失敗但日誌顯示無異常的原因:方法要返回’success‘,並且不能直接return 'success',要使用response輸出’success‘。
注:
1. TOKEN , ENCODING_AES_KEY, THIRD_PARTY_APP_ID 都是第三方的配置參數
其中TOKEN爲消息校驗Token, ENCODING_AES_KEY爲消息加解密Key, THIRD_PARTY_APP_ID 爲第三方平臺的app_id
2.注意要把自己測試的機子的ip在自己的微信開發平臺第三方平臺里加入白名單
3. 測試
登入微信開放平臺https://open.weixin.qq.com/
登入賬號進入第三方平臺,點擊全網發佈
點擊確認後可進行測試。
參考文檔:授權流程技術說明 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1453779503&token=&lang=