参考:企业微信-回调配置(一)
官方demo参考:
使用企业微信提供了解密、加密、验证URL三个接口
1、数据回调校验和指令回调校验
这个都是GET请求校验。
参考:官方API文档:3.1 支持Http Get请求验证URL有效性
注意点:在1秒内响应GET请求,响应内容为上一步得到的明文消息内容(不能加引号,不能带bom头,不能带换行符)
这里必须使用HttpServletResponse来响应,使用@RestController的return返回值不能识别,可能是因为加了引号的原因。
HttpServletResponse.write(sEchoStr);
2、刷新Ticket
参考:官方API文档:3.2 支持Http Post请求接收业务数据
注意点:
- CorpID = “SuiteID”; //这里要使用SuiteID第三方应用的id。
- 官方提供的工具类里,获取参数名称的不对,最新的ToUserName,AgentID,Encrypt是驼峰名称,原来的都是小写的。
- post请求体的格式xml,使用官方工具类是,需要先把xml转换成JSON字符串,再给工具类处理
- 解密Encrypt,得到明文的消息结构体也是xml格式的,如果要获取里面的数据,也需要进行解析。
- 响应也必须使用HttpServletResponse.write();
参数说明:
参数 | 类型 | 说明 |
---|---|---|
msg_signature | String | 企业微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体 |
timestamp | Integer | 时间戳。与nonce结合使用,用于防止请求重放攻击。 |
nonce | String | 随机数。与timestamp结合使用,用于防止请求重放攻击。 |
ToUserName | String | 企业微信的CorpID,当为第三方应用回调事件时,CorpID的内容为suiteid |
AgentID | String | 接收的应用id,可在应用的设置页面获取。仅应用相关的回调会带该字段。 |
Encrypt | String | 消息结构体加密后的字符串 |
附录:JAVA代码
package com.tj.qywx.controller;
import com.alibaba.fastjson.JSON;
import com.github.wxpay.sdk.WXPayUtil;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizJsonMsgCrypt;
import com.tj.base.service.BaseNumvarService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
@Slf4j //日志
@RestController //RESTful风格写法
@RequestMapping("/wxCallback") //定义API接口
public class WxCallbackCtrl {
@Autowired
private BaseNumvarService baseNumvarService;
/**
* 数据回调
*
* @param msg_signature 企业微信加密签名,msg_signature计算结合了企业填写的token、请求中的timestamp、nonce、加密的消息体。签名计算方法参考 消息体签名检验
* @param timestamp 时间戳。与nonce结合使用,用于防止请求重放攻击
* @param nonce 随机数。与timestamp结合使用,用于防止请求重放攻击。
* @param echostr 加密的字符串。需要解密得到消息内容明文,解密后有random、msg_len、msg、receiveid四个字段,其中msg即为消息内容明文
*/
@GetMapping
void getDataCheck(String msg_signature,
String timestamp,
String nonce,
String echostr,
HttpServletResponse response) throws AesException, IOException {
String sToken = "应用设置的token";
String sCorpID = baseNumvarService.getCorpid();
String sEncodingAESKey = "应用设置的key";
PrintWriter out = response.getWriter();
//调用微信官方提供的工具类
WXBizJsonMsgCrypt wxcpt = new WXBizJsonMsgCrypt(sToken, sEncodingAESKey, sCorpID);
String sEchoStr; //需要返回的明文
try {
sEchoStr = wxcpt.VerifyURL(msg_signature, timestamp,
nonce, echostr);
log.info("verifyurl echostr: {}", sEchoStr);
// 验证URL成功,将sEchoStr返回,这个地方必须这样返回,什么都不要加,不能加引号
out.write(sEchoStr);
out.close();
} catch (Exception e) {
//验证URL失败,错误原因请查看异常
e.printStackTrace();
}
}
/**
* 刷新Ticket
*
* @param msg_signature 企业微信加密签名,msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体
* @param timestamp 时间戳。与nonce结合使用,用于防止请求重放攻击。
* @param nonce 随机数。与timestamp结合使用,用于防止请求重放攻击。
* @param xmlData ToUserName String 企业微信的CorpID,当为第三方应用回调事件时,CorpID的内容为suiteid
* AgentID String 接收的应用id,可在应用的设置页面获取。仅应用相关的回调会带该字段。
* Encrypt String 消息结构体加密后的字符串
* @return
* @throws AesException
*/
@PostMapping
void postActionCheck(String msg_signature,
String timestamp,
String nonce,
@RequestBody String xmlData,
HttpServletResponse response) throws IOException {
String sToken = "应用设置的token";
String sCorpID = "SuiteID"; //这里要使用SuiteID第三方应用的id
String sEncodingAESKey = "应用设置的key";
log.info("msg_signature:{}", msg_signature);
log.info("timestamp:{}", timestamp);
log.info("nonce:{}", nonce);
log.info("xmldata的值:{}", xmlData);
PrintWriter out = response.getWriter();
try {
//调用微信官方提供的工具类
WXBizJsonMsgCrypt wxcpt = new WXBizJsonMsgCrypt(sToken, sEncodingAESKey, sCorpID);
//把xml转换成json格式
Map<String, String> map = WXPayUtil.xmlToMap(xmlData);
String jsonString = JSON.toJSONString(map);
log.info("xml转JSON后的字符串的值:{}", jsonString);
/* 官方工具类解析这个几个字符的时候,需要注意,字段名称大小写不一样了。要改成下面的这样的
String encrypt_msg = json.getString("Encrypt");
String tousername = json.getString("ToUserName");
String agentid = json.getString("AgentID");
*/
String sMsg = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, jsonString);
log.info("解密后的xml信息:{} ", sMsg);
// 获取SuiteTicket
Map<String, String> msgMap = WXPayUtil.xmlToMap(sMsg);
String SuiteTicket = msgMap.get("SuiteTicket");
log.info("SuiteTicket:{}", SuiteTicket);
} catch (Exception e) {
// TODO
// 解密失败,失败原因请查看异常
e.printStackTrace();
}
out.write("success");
out.close();
}
}