企业微信三方开发(一):回调验证及重要参数获取 |
您所在的位置:网站首页 › 微信url地址是什么意思啊怎么设置 › 企业微信三方开发(一):回调验证及重要参数获取 |
Git 地址:https://gitee.com/tantantantan/cwp.git —————————————————————— 其他链接 初识微信开发 企业微信三方开发:注册企业微信服务商 企业微信三方开发(一):回调验证及重要参数获取 企业微信三方开发(二):获取access_token 企业微信三方开发(三):网页授权登录 企业微信三方开发(四):发送消息 企业微信三方开发(五):扫码登录 目录 前言技术栈及工具一、后台配置应用回调配置通用开发参数回调配置 二、构建spring-boot项目新建项目项目目录结构导入加解密包 写验证类1、回调验证2、获取suite_ticket及auth_code 总结 前言 我们在新建好一个网页应用后,需要填一些基础配置。其中最重要的就是一些回调配置,回调路径指向我们自己的服务器,需要正确接收响应微信服务器的请求。微信接口开发无非就是通过一些带token的http请求来实现相关功能,而获取这些token往往需要先获取一些重要参数,这里有两个参数需要先获取:suite_ticket 和 auth_code对微信开发不熟,或者没读我之前文章的同学一定要搞清一个概念:在三方应用开发中,应用开发方统称三方服务商,对应id我会称 【服务商corpId】;应用使用方称作 企业,对应id叫 【企业corpId】。请不要搞混了 技术栈及工具 开发框架:spring-boot开发工具: idea 一、后台配置 应用回调配置首先我们进入新建的应用: 共有四个配置项,分别是: 两个回调URLToken(密钥,不可泄漏)EncodingAESKey(加密消息内容的码)这里的URL就是我们服务器的响应路径,微信服务器会根据这里的URL向我们服务器发送请求,我们服务器验证方面需要做两件事: 分辨出是否为企业微信来源分辨出推送消息的内容是否被篡改填写好回调URL,并选择自动生成Token和EncodingAESKey 简单一句话概括就是,在某些时点(具体什么时点或访问哪个回调请看下面 “写VerifyController类” 内容),微信服务器会向我们服务器发送验证请求,我们服务器需要通过Token、EncodingAESKey和服务商CorpID计算Signature与GET请求参数中的Signature作对比,如果一样就验证通过,返回"success"。 具体的加密计算方法不再赘述,自己阅读文档。企业微信为我们集成好了加解密的包,我们拿之即用就行: https://work.weixin.qq.com/api/doc/90000/90138/90307 通用开发参数回调配置还有一个重要参数需要设置,就是 通用开发参数 里的 系统事件接收URL。 当 企业 安装应用时,微信服务器会向这个 系统事件接收URL 发送验证请求,我们需要做的响应跟上面的应用回调验证基本一样。 所以我将两者URL、Token、EncodingAESKey设为一样,通过同一个接口来处理这两种请求。 由于后台还未搭建,这些设置都保存不了,接下来我们先搭建后台。 二、构建spring-boot项目Spring Boot的出现简直就是像我这样的后端渣渣的福音,我们可以很快速的构建一个服务系统。所以我很愉快的选择了它! 还有很重要的一点,本系列文重在打通企业微信的一些功能,以及验证一些逻辑。代码尽量简洁。所以我暂时不会遵循实战项目的设计逻辑,也缺少一些排错处理。请读者知悉! 新建项目新建一个项目:cwp(company wechat project之意) 并新建一些必要的包和类,具体目录结构如下: 还记的之前说过的企业微信给的加密计算方法实例吗? 微信准备了xml和json两种解密方式。这里选择Java的xml方式。将验证包中的类全部考入 wechataes包 中: 此类有两个方法: doGetValid : 接收验证请求,用于验证通用开发参数系统事件接收URL、数据回调URL、指令回调URL。当企业微信后台录入回调URL点击保存时,微信服务器会立即发送一条GET请求到对应URL,该函数就对URL的signature进行验证。doPostValid: 用于获取 suite_ticket ,以及安装应用时传递过来的 auth_code ,还有用户从企业微信打开应用时也会调用此函数。解密包的第三个参数需做区分:当刷新ticket和安装应用时传递 【SuitID】 ;当打开应用时传递 【CorpID】再来捋一下,数据回调和指令回调除了保存配置时被访问,还有哪些情况会被微信服务器访问: 数据回调URL: 当每次从企业微信打开应用时。【doPostValid 中的解密参数传递CorpID】指令回调URL: 微信服务器推送suite_ticket以及安装应用时推送auth_code时。【doPostValid 中的解密参数传递SuitID】 1、回调验证doGetValid方法如下: package com.tan.cwp.controller; import com.tan.cwp.config.Constant; import com.tan.cwp.wechataes.WXBizMsgCrypt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; @RestController @RequestMapping("/verify") public class VerifyController { Logger logger = LoggerFactory.getLogger(VerifyController.class); /* * 验证通用开发参数及应用回调 */ @RequestMapping(value = "callback_verify.do" ,method = RequestMethod.GET) public void doGetValid(HttpServletRequest request, HttpServletResponse response) throws Exception { // 微信加密签名 String msg_signature = request.getParameter("msg_signature"); // 时间戳 String timestamp = request.getParameter("timestamp"); // 随机数 String nonce = request.getParameter("nonce"); // 随机字符串 // 如果是刷新,需返回原echostr String echostr = request.getParameter("echostr"); WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(Constant.TOKEN, Constant.EncodingAESKey, Constant.CorpID); String sEchoStr=""; //需要返回的明文 PrintWriter out; try { sEchoStr = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr); logger.info("verifyurl echostr: " + sEchoStr); // 验证URL成功,将sEchoStr返回 out = response.getWriter(); out.print(sEchoStr); } catch (Exception e) { //验证URL失败,错误原因请查看异常 e.printStackTrace(); } } }在后台录入好接口URL保存时,微信后台即会向该接口发送GET请求,并携带四个参数:msg_signature、timestamp、nonce、echostr。 通过 request.getParameter(xxx)获取到他们。 还需要从企业微信后台获取三个固定参数用于计算singnature:TOKEN、EncodingAESKey、CorpID 我把固定参数都放在 配置类Constant 中: package com.tan.cwp.config; public class Constant { // 服务商相关 /** * 服务商CorpID */ public static final String CorpID = "xxxx"; /** * 服务商身份的调用凭证 */ public static final String ProviderSecret = "xxxx"; // 应用相关 /** * 应用的唯一身份标识 */ public static final String SuiteID = "xxxx"; /** * 应用的调用身份密钥 */ public static final String SuiteSecret = "xxxx"; // 回调相关 /** * 回调/通用开发参数Token, 两者解密算法一样,所以为方便设为一样 */ public static final String TOKEN = "xxxx"; /** * 回调/通用开发参数EncodingAESKey, 两者解密算法一样,所以为方便设为一样 */ public static final String EncodingAESKey = "xxxx"; }有了这些重要参数就可以通过企业微信准备的包进行验证了。运行项目,并点击申请验证:
两者获取方式完全相同,微信服务器会通过POST请求向我们服务器传递:msg_signature,timestamp,nonce,echostr四个参数 ,同样通过 request.getParameter(xxx)获取。 同时还会传递一个加密过的xml格式的请求体,通过输入流方式获取该参数,并通过企业微信的验证包进行解密。 具体解密过程查看 doPostValid 方法: package com.tan.cwp.controller; import com.tan.cwp.config.Constant; import com.tan.cwp.util.PropertiesUtil; import com.tan.cwp.util.WxUtil; import com.tan.cwp.wechataes.WXBizMsgCrypt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.Iterator; import java.util.Map; @RestController @RequestMapping("/verify") public class VerifyController { Logger logger = LoggerFactory.getLogger(VerifyController.class); /** * 验证通用开发参数 */ @RequestMapping(value = "callback_verify.do" ,method = RequestMethod.GET) public void doGetValid(HttpServletRequest request, HttpServletResponse response) throws Exception { // 微信加密签名 String msg_signature = request.getParameter("msg_signature"); // 时间戳 String timestamp = request.getParameter("timestamp"); // 随机数 String nonce = request.getParameter("nonce"); // 随机字符串 // 如果是刷新,需返回原echostr String echostr = request.getParameter("echostr"); WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(Constant.TOKEN, Constant.EncodingAESKey, Constant.CorpID); String sEchoStr=""; //需要返回的明文 PrintWriter out; try { sEchoStr = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr); // 验证URL成功,将sEchoStr返回 out = response.getWriter(); out.print(sEchoStr); } catch (Exception e) { //验证URL失败,错误原因请查看异常 e.printStackTrace(); } } /** * 刷新 ticket */ @RequestMapping(value = "callback_verify.do" ,method = RequestMethod.POST) public String doPostValid(HttpServletRequest request) throws Exception { // 微信加密签名 String msg_signature = request.getParameter("msg_signature"); // 时间戳 String timestamp = request.getParameter("timestamp"); // 随机数 String nonce = request.getParameter("nonce"); String type = request.getParameter("type"); String id = ""; // 访问应用和企业回调传不同的ID if(type.equals("data")){ id = Constant.CorpID; } else { id = Constant.SuiteID; } WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(Constant.TOKEN, Constant.EncodingAESKey, id); String postData=""; // 密文,对应POST请求的数据 //1.获取加密的请求消息:使用输入流获得加密请求消息postData ServletInputStream in = request.getInputStream(); BufferedReader reader =new BufferedReader(new InputStreamReader(in)); String tempStr=""; //作为输出字符串的临时串,用于判断是否读取完毕 while(null!=(tempStr=reader.readLine())){ postData+=tempStr; } String suiteXml=wxcpt.DecryptMsg( msg_signature, timestamp, nonce, postData); logger.info("suiteXml: " + suiteXml); Map suiteMap = WxUtil.transferXmlToMap(suiteXml); if(suiteMap.get("SuiteTicket") != null) { PropertiesUtil.setProperty("suite_ticket", (String) suiteMap.get("SuiteTicket")); } else if(suiteMap.get("AuthCode") != null){ PropertiesUtil.setProperty("auth_code", (String) suiteMap.get("AuthCode")); } String success = "success"; return success; } }注意这段: 里面用到了dom4J,需要在pom.xml中引入: org.jdom jdom2 2.0.6由于并不急着打通数据库,这里通过 PropertiesUtil类 动态的读取和写入获取到的参数到 data.properties中: package com.tan.cwp.util; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Properties; public class PropertiesUtil { private static Logger logger = LoggerFactory.getLogger(PropertiesUtil.class); private static Properties props; private static String fileName = "data.properties"; private static String path ="D:/Nobug/WeChat/backend/cwp/src/main/resources/data.properties"; static { props = new Properties(); try { props.load(new InputStreamReader(PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName),"UTF-8")); } catch (IOException e) { logger.error("配置文件读取异常",e); } } // 读取参数 public static String getProperty(String key){ String value = props.getProperty(key.trim()); if(StringUtils.isBlank(value)){ return null; } return value.trim(); } // 写入参数 public static String setProperty(String key, String value) throws IOException { props.setProperty(key, value); FileOutputStream file = new FileOutputStream(path); props.store(file,"refresh"); return null; } }pom.xml需要引入commons-lang3 org.apache.commons commons-lang3 3.5记住要先在data.properties中放好suite_ticket和auth_code: 再次运行项目,我们先获取suite_ticket: 我们再试下安装测试: 通过企业微信扫码安装后,显示安装成功: 在第三方应用开发提供的接口中,主要围绕三种类型的access_token进行开发: provider_access_token 服务商的tokensuite_access_token 第三方应用的tokenaccess_token 授权企业的token通过今天的配置和获取到SuiteTicket和AuthCode后,接下来要做的就是通过一系列HTTP请求来愉快获取这些token! 2020/10/7重要更正: |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |