一、关于设置接收事件服务器的信息
在企业微信管理后台的“客户联系-客户”页面,点开“API”小按钮,再点击“接收事件服务器”配置,进入配置页面,要求填写URL、Token、EncodingAESKey三个参数。
- URL是企业后台接收企业微信推送请求的访问协议和地址,支持http或https协议(建议使用https)。
- Token可由企业任意填写,用于生成签名。
- EncodingAESKey用于消息体的加密,是AES密钥的Base64编码。
如下图所示:
从以上图,我们可以知道这里配置的信息,是配置我们本地的路径,远程企业微信外部联系人变更,会推送到我们本地,进而处理我们需要的数据。
问题:A、url配置的路径是怎么样的?
B、推送到本地数据的路径是否也是URL配置路径?
二、解决思路
针对A、B问题,远程URL配置首先需要验证URL的有效性,其次再是消息的推送。详情说明请看:关于接收消息
本地实现策略:定义一个路径,既符合GET请求又符合POST请求,可以定义两个方法,相同的请求路径,分GET请求和POST请求。对于加密解密,这里不在赘述。
如下所示:
/**
* 外部联系人业务处理
* @param cropId
* @return
*/
@PostMapping(value = "/callback/external-user/{cropId}")
public String callbackExternalUserMsg(HttpServletRequest request, HttpServletResponse response, @PathVariable String cropId,@RequestBody String postData){
log.info("企业微信CorpId:{},企业微信外部联系人事件消息通知:\n {} ",cropId,postData);
String encodingAesKey = qyEncodingAesKey;
String token = qyToken;
try {
JAXBContext context = JAXBContext.newInstance(QyCustVo.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
QyCustVo msgVo = (QyCustVo) unmarshaller.unmarshal(new StringReader(postData));
msgVo.setXmlStr(postData);
if (StringUtil.isNotEmpty(msgVo.getEncrypt())) {
String nonce = request.getParameter("nonce");
String timestamp = request.getParameter("timestamp");
String msgSignature = request.getParameter("msg_signature");
log.info("企业微信加密签名:{},时间戳:{},随机数:{}" , msgSignature,timestamp,nonce);
WxAESInfo wxcpt = new WxAESInfo(cropId, encodingAesKey, token);
String result = WxAESUtil.decryptMsg(wxcpt, msgVo.getEncrypt(), msgSignature, timestamp, nonce);
msgVo = (QyCustVo) unmarshaller.unmarshal(new StringReader(result));
msgVo.setXmlStr(result);
log.info("接收事件消息解密后的消息体:{}",result);
}
if (StringUtil.isNotBlank(msgVo.getXmlStr())){
String topic = "qywxopen-externalUserMsg";
boolean sendMessage = mqService.sendMessage(topic, msgVo.getXmlStr(), false);
log.info("外部联系人变更回调的kafka主题:{},发送的状态:{}",topic,sendMessage);
}
}catch (Exception e){
e.printStackTrace();
}
return "success";
}
/**
* 外部联系人URL路径校验
* @param request
* @param response
* @param cropId
* @throws IOException
*/
@RequestMapping(value = "/callback/external-user/{cropId}", method = RequestMethod.GET)
public void callbackExternalUser(HttpServletRequest request, HttpServletResponse response, @PathVariable String cropId) throws IOException {
log.info("企业微信CorpId:{}",cropId);
String encodingAesKey =qyEncodingAesKey.trim();
String token = qyToken.trim();
String nonce = request.getParameter("nonce").trim();
String timestamp = request.getParameter("timestamp").trim();
String msgSignature = request.getParameter("msg_signature").trim();
String echostr = request.getParameter("echostr").trim();
echostr = echostr.replace(" ", "+");
log.info("企业微信加密签名:{},时间戳:{},随机数:{},加密的字符串:{}" , msgSignature,timestamp,nonce,echostr);
String result = null;
PrintWriter printWriter = response.getWriter();
try {
WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(token,encodingAesKey,cropId);
result = wxBizMsgCrypt.verifyUrl(msgSignature,timestamp,nonce,echostr);
log.info("验证URL解密后的消息体:\n{}",result);
}catch (Exception e){
e.printStackTrace();
}
if (StringUtil.isEmpty(result)){
result = "success";
}
printWriter.print(result);
printWriter.close();
}