最近老板下发了个任务,有一个业务是整合用户的微信公众号(服务号),然后在我们的erp系统里给下家客户发送模板消息,找了一下发现微信第三方平台可以实现,那就干起来。
先在微信开放平台,申请一个第三方平台服务。
然后通过下面几步实现消息推送1 、微信验证接口,拿到 ticket
2 、拿到调用令牌 component_access_token
3 、获取预授权码 pre_auth_code
4 、扫码授权,获取授权码 auth_code
5 、通过授权码拿到调用令牌(authorizer_access_token)和刷新令牌(authorizer_refresh_token)
6 、通过 authorizer_access_token 实现消息推送
1、验证接口代码
@RequestMapping("getTicket")public String componentVerifyTicket(HttpServletRequest request, HttpServletResponse response) throws Exception{log.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();log.info("nonce: " + nonce);log.info("timestamp: " + timestamp);log.info("msgSignature: " + msgSignature);log.info("postData: " + postData);getComponentVerifyTicket(timestamp, nonce, msgSignature, postData);return "success";}
public static void getComponentVerifyTicket(String timestamp, String nonce, String msgSignature, String postData) throws Exception {// 需要加密的明文// COMPONENT_TOKEN token// aesKey 加密密钥WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, aesKey, appId);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);log.info("解密后: " + result);Map<String, String> map = XMLUtil.doXMLParse(result);String componentVerifyTicket = map.get("ComponentVerifyTicket");System.out.println("获取ticket====="+componentVerifyTicket);}
XMLUtil
/*** 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。** @param strxml* @return* @throws JDOMException* @throws IOException*/public static Map doXMLParse(String strxml) throws JDOMException, IOException {strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");if (null == strxml || "".equals(strxml)) {return null;}Map m = new HashMap();InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));SAXBuilder builder = new SAXBuilder();Document doc = builder.build(in);Element root = doc.getRootElement();List list = root.getChildren();Iterator it = list.iterator();while (it.hasNext()) {Element e = (Element) it.next();String k = e.getName();String v = "";List children = e.getChildren();if (children.isEmpty()) {v = e.getTextNormalize();} else {v = XMLUtil.getChildrenText(children);}m.put(k, v);}//关闭流in.close();return m;}/*** 获取子结点的xml** @param children* @return String*/public static String getChildrenText(List children) {StringBuffer sb = new StringBuffer();if (!children.isEmpty()) {Iterator it = children.iterator();while (it.hasNext()) {Element e = (Element) it.next();String name = e.getName();String value = e.getTextNormalize();List list = e.getChildren();sb.append("<" + name + ">");if (!list.isEmpty()) {sb.append(XMLUtil.getChildrenText(list));}sb.append(value);sb.append("</" + name + ">");}}return sb.toString();}
2、拿到调用令牌 component_access_token
微信文档链接:
https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/ticket-token/getComponentAccessToken.html
通过上一步拿到的ticket,传入第三方的appid和appsecret ,调用微信接口获取第三方的调用令牌:
component_access_tokenhttps://api.weixin.qq.com/cgi-bin/component/api_component_token{"component_appid": "*****" , // 第三方平台appid"component_appsecret": "*****", // 密钥"component_verify_ticket":""}
3、拿到component_access_token后再次调用接口获取预授权码
微信文档:
https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/ticket-token/getPreAuthCode.html
ACCESS_TOKEN: 就是上一步获取到的component_access_tokenhttps://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?access_token=ACCESS_TOKEN{"component_appid": "wxe7986597a6b2a7e4"}
4、通过预授权码生成链接,管理员扫码后授权获取授权码
将上一步获取到的预授权吗填入下面:
https://mp.weixin.qq.com/cgi-bin/componentloginpage?
component_appid=wxe7986597a6b2a7e4
&pre_auth_code=preauthcode@@@IbLBSSV_2LkGjtZKk8aPCFc4JI2Wzzawfj6tse60aktFdrTD1oP_nWNULntkhPjHKvp3Ae1GnL4sReu_7A2zjA
&redirect_uri=http://ys99.top/bed/wx/getAuthCode
component_appid:第三方平台的appid
pre_auth_code:上一步拿到的预授权码
redirect_uri:授权后重定向地址,接口里拿到正式的授权码 queryauthcode
然后通过a链接打开就可以了
5、通过授权码获取第三方公众号的授权令牌 authorizer_access_token
https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=******{"component_appid":"wxe7986597a6b2a7e4","authorization_code":"queryauthcode@@@qCsx1osdrsQRn7LoiLVOIz3Ut273KrqYJlT9cdbQS3lCupjsPvFcaAbaT3zHG2EDhCgJ3dUw94gbgrOOTFhl_g"
}
6、通过上一步获取到了公众号的调用令牌authorizer_access_token
后续的公众号所有操作都使用这个令牌https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=
66_Ew0rFnSUMD56EEsZBk8aVTteynjtjojSliKpAIvBd8AR750VvN0O3puNI2srbPAIlkesBainkEBJTT4dRQWVQbxf2wuFB_om-mgJ-AXxZ26gJKjIAdPpNIQzkUOX9x8TJllWGBqU2Fr7oR16OCNaAHDAOZ
access_token:就是上一步获取到的调用令牌
touser:用户在微信公众号的openid
template_id:在公众号的消息模板id