准备工作
先下载demo
下载完成后的目录,把这些类之间copy到工程里面就行,都是封装好的加密算法
回调配置
什么时候需要回调
在集成企业微信与内部系统时,我们往往需要搭建一个回调服务。回调服务,可以实现:
自定义丰富的服务行为。比如,用户向应用发消息时,识别消息关键词,回复不同的消息内容;用户点击应用菜单时,转化为指令,执行自动化任务。
可以及时获取到状态变化。比如,通讯录发生变化时,不需要定时去拉取通讯录对比,而是实时地获取到变化的通讯录结点,进行同步。
回调服务需要哪些配置
配置回调服务,需要有三个配置项,分别是:URL, Token, EncodingAESKey。
首先,URL为回调服务地址,由开发者搭建(需要满足接口要求,参考第3部分说明),用于接收通知消息或者事件。
其次,Token用于计算签名,由英文或数字组成且长度不超过32位的自定义字符串。开发者提供的URL是公开可访问的,这就意味着拿到这个URL,就可以往该链接推送消息。
最后,EncodingAESKey用于消息内容加密,由英文或数字组成且长度为43位的自定义字符串。由于消息是在公开的因特网上传输,消息内容是可被截获的,如果内容未加密,则截获者可以直接阅读消息内容。若消息内容包含一些敏感信息,就非常危险了。EncodingAESKey就是在这个背景基础上提出,将发送的内容进行加密,并组装成一定格式后再发送。
回调逻辑实现
需要有2个回调接口,
一个get请求,用来验证url 是否有效
一个post请求,用来接收回调数据
企业微信会先判断URL服务是否具备解析企业微信推送消息的能力。
具体方式是,企业微信往URL服务上发一条Get请求带签名及密文参数到URL服务上,如果URL服务检查签名通过,并能正确返回密文参数对应的明文字符串,则验证通过。此时在企业微信的配置就开始生效。
后续的业务请求(比如应用菜单的点击事件,用户消息等),都会类似的方式(签名+密文)向服务URL推送消息。URL服务验证签名通过后,需要将POST数据解密,就可以得到对应的业务消息明文。
话不多说,直接上代码,准备2个接口
/**
* 验证微信回调地址
*
* @author: what
*/
String verifyURL(String msgSignature, String timestamp, String nonce, String echostr);
/**
* 企业微信回调数据
*
* @author: what
*/
String decryptMsg(String msgSignature, String timestamp, String nonce, String postData);
实现类
定义常量
public static final String CHANGE_TYPE = "ChangeType";
public static final String CHANGE_TYPE_USER = "_user";
public static final String CHANGE_TYPE_ORG = "_party";
public static final String CHANGE_TYPE_ACTION_CREATE = "create";
public static final String CHANGE_TYPE_ACTION_UPDATE = "update";
public static final String CHANGE_TYPE_ACTION_DELETE = "delete";
public static final String DATA_CHANGE_TYPE_USER = "UserID";
public static final String DATA_CHANGE_TYPE_ORG = "ParentId";
public static final String ERR_CODE = "errcode";
public static final String ERR_MSG = "errmsg";
public static final String UTF_8 = "utf-8";
public static final String APPLICATION = "application/json";
public static final String SECRET = "xJLwef4564dfgjc19fdfghd245sddfs-XSc";
public static final String HTTP_URL_CREATE_USER = "https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token=";
public static final String HTTP_URL_UPDATE_USER = "https://qyapi.weixin.qq.com/cgi-bin/user/update?access_token=";
public static final String HTTP_URL_DELETE_USER = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete?access_token=";
public static final String HTTP_URL_CREATE_ORG = "https://qyapi.weixin.qq.com/cgi-bin/department/create?access_token=";
public static final String HTTP_URL_UPDATE_ORG = "https://qyapi.weixin.qq.com/cgi-bin/department/update?access_token=";
public static final String HTTP_URL_DELETE_ORG = "https://qyapi.weixin.qq.com/cgi-bin/department/delete?access_token=";
String sToken = callbackToken;--这个对应下图中的Token
String sCorpID = appid;--这个对应企业ID
String sEncodingAESKey = callbackAesKey;--这个对应下图中的EncodingAESKey
验证url是否有效,用于get请求
/**
* 验证微信回调地址
*
* @author: what
*/
@Override
public String verifyURL(String msgSignature, String timestamp, String nonce, String echostr){
String sToken = callbackToken;
String sCorpID = appid;
String sEncodingAESKey = callbackAesKey;
WXBizMsgCrypt wxcpt = null;
String sEchoStr = null;
try {
wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
sEchoStr = wxcpt.verifyURL(msgSignature, timestamp, nonce, echostr);
log.info("验证微信回调地址------------------" + sEchoStr);
} catch (AesException e) {
e.printStackTrace();
}
return sEchoStr;
}
接收回调数据,用于post请求
/**
* 企业微信回调数据(返回的数据是xml格式,需要把xml转换成json格式)
*
* @author: what
*/
@Override
public String decryptMsg(String msgSignature, String timestamp, String nonce, String postData){
String result = "企业微信通讯录回调成功";
String sToken = callbackToken;
String sCorpID = appid;
String sEncodingAESKey = callbackAesKey;
WXBizMsgCrypt wxcpt = null;
String sMsg = "";
try {
wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
sMsg = wxcpt.decryptMsg(msgSignature, timestamp, nonce, postData);
if(StringUtils.isNotBlank(sMsg)){
JSONObject jsonObject = Xml2JsonTool.xmltoJson(sMsg);
JSONObject xml = jsonObject.getJSONObject("xml");
//如果包含UserID,就是用户数据变更,如果包含ParentId,就是部门数据变更
if(sMsg.indexOf(PubConstant.DATA_CHANGE_TYPE_USER) > 0){
if(xml.getString(PubConstant.CHANGE_TYPE).equals(PubConstant.CHANGE_TYPE_ACTION_CREATE + PubConstant.CHANGE_TYPE_USER)){
//添加用户逻辑
}else if(xml.getString(PubConstant.CHANGE_TYPE).equals(PubConstant.CHANGE_TYPE_ACTION_UPDATE + PubConstant.CHANGE_TYPE_USER)){
//修改用户逻辑
}else if(xml.getString(PubConstant.CHANGE_TYPE).equals(PubConstant.CHANGE_TYPE_ACTION_DELETE + PubConstant.CHANGE_TYPE_USER)){
//删除用户逻辑
}
}else if(sMsg.indexOf(PubConstant.DATA_CHANGE_TYPE_ORG) > 0){
if(xml.getString(PubConstant.CHANGE_TYPE).equals(PubConstant.CHANGE_TYPE_ACTION_CREATE + PubConstant.CHANGE_TYPE_USER)){
//添加部门逻辑
}else if(xml.getString(PubConstant.CHANGE_TYPE).equals(PubConstant.CHANGE_TYPE_ACTION_UPDATE + PubConstant.CHANGE_TYPE_USER)){
//修改部门逻辑
}else if(xml.getString(PubConstant.CHANGE_TYPE).equals(PubConstant.CHANGE_TYPE_ACTION_DELETE + PubConstant.CHANGE_TYPE_USER)){
//删除部门逻辑
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
controller
get请求,用于验证url有效
@ApiOperation(value = "企业微信回调接口验证", notes = "对接人:what")
@RequestMapping(value = "/callback", method = RequestMethod.GET, produces = "application/json")
public void reveiceMsg(
@RequestParam(name = "msg_signature") final String msgSignature,
@RequestParam(name = "timestamp") final String timestamp,
@RequestParam(name = "nonce") final String nonce,
@RequestParam(name = "echostr") final String echostr,
final HttpServletResponse response) throws Exception {
String sEchoStr = wxService.verifyURL(msgSignature, timestamp, nonce, echostr);
PrintWriter out = response.getWriter();
try {
//必须要返回解密之后的明文
if (StringUtils.isNotBlank(sEchoStr)) {
log.info("企业微信回调接口验证成功~~~");
} else {
log.info("企业微信回调接口验证失败!!!");
}
} catch (Exception e) {
e.printStackTrace();
}
out.write(sEchoStr);
out.flush();
}
post请求用户接收回调数据
@ApiOperation(value = "企业微信回调接口", notes = "对接人:what")
@RequestMapping(value = "/callback", method = RequestMethod.POST, produces = "application/json")
public JsonResult reveiceMsg(final HttpServletRequest request,
@RequestParam(name = "msg_signature") final String sMsgSignature,
@RequestParam(name = "timestamp") final String sTimestamp,
@RequestParam(name = "nonce") final String sNonce) throws Exception {
InputStream inputStream = request.getInputStream();
String sPostData = IOUtils.toString(inputStream, "UTF-8");
log.info("回调数据返回================" + sPostData);
String sEchoStr = wxService.decryptMsg(sMsgSignature, sTimestamp, sNonce, sPostData);
return JsonResult.ok(sEchoStr);
}
配置回调域名
一定要记得配置url,必须是备案域名,还有就是ip可信名单,其他的按照这里写基本就没问题了