# Java 企业微信回调配置
企业微信 API 文档地址:https://open.work.weixin.qq.com/api/doc/90001/90143/91116
# 获取 Token 和 EncodingAESKey
登录企业微信后台。
1:点击右下角图标打开网页进入
2:打开工作台,打开应用,点击右上角图标进入 (图标和下图右下角图标一样)
打开需要配置的应用,点击 启用API接收
随机生成 Token 和 EncodingAESKey
# 准备 URL 接口
两个接口,相同路径,一个 GET
一个 POST
请求。上面调用的是 GET
请求判断 URL 服务是否具备解析能力,通过后保存成功,之后调用 POST
请求
接口内容如下
import cn.hutool.core.util.XmlUtil; | |
import org.apache.commons.io.IOUtils; | |
import org.apache.commons.lang3.StringUtils; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.web.bind.annotation.GetMapping; | |
import org.springframework.web.bind.annotation.PostMapping; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RestController; | |
import org.springframework.web.servlet.mvc.support.RedirectAttributes; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import javax.servlet.http.HttpSession; | |
import java.io.InputStream; | |
import java.io.PrintWriter; | |
import java.nio.charset.StandardCharsets; | |
import java.util.Map; | |
@RestController | |
@RequestMapping("/api/wx") | |
public class WxSampleController { | |
private static final Logger logger = LoggerFactory.getLogger(WxSampleController.class); | |
/** 企业微信回调验证 */ | |
@GetMapping("/callback") | |
public void connect(HttpServletRequest request, HttpServletResponse response){ | |
//msg_signature = hash 算法 (token+timestamp+nonce+echostr); | |
// 形象说法就是标记,防止参数传递过程被篡改 | |
String msg_signature = request.getParameter("msg_signature");// 微信加密签名 | |
String timestamp = request.getParameter("timestamp");// 时间戳 | |
String nonce = request.getParameter("nonce");// 随机数 | |
//echostr = AES 算法使用 EncodingAESKey 密钥加密明文后的值 | |
String echoStr = request.getParameter("echostr");// 随机字符串 | |
String token = ""; // 前面获取的 Token | |
String encodingaeskey = ""; // 前面获取的 EncodingAESKey | |
String secretId = ""; // 企业 ID | |
try (PrintWriter out = response.getWriter()) { | |
// 微信准备的加解密类 | |
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token,encodingaeskey,secretId); | |
String sEchoStr = wxcpt.VerifyURL(msg_signature,timestamp,nonce,echoStr); | |
if(StringUtils.isBlank(sEchoStr)){ | |
logger.error("URL验证失败"); | |
} | |
out.write(sEchoStr); | |
out.flush(); | |
}catch (Exception e){ | |
logger.error("企业微信回调url验证错误",e); | |
} | |
} | |
/** 企业微信消息交互 */ | |
@PostMapping( "/callback") | |
public void acceptMessage(HttpServletRequest request, RedirectAttributes attributes, HttpSession session){ | |
//msg_signature = hash 算法 (token+timestamp+nonce+echostr); | |
// 形象说法就是标记,防止参数传递过程被篡改 | |
String sMsgSignature = request.getParameter("msg_signature");// 微信加密签名 | |
String sTimestamp = request.getParameter("timestamp");// 时间戳 | |
String sNonce = request.getParameter("nonce");// 随机数 | |
String token = ""; // 前面获取的 Token | |
String encodingaeskey = ""; // 前面获取的 EncodingAESKey | |
String corpId = ""; // 企业 ID | |
try{ | |
InputStream inputStream = request.getInputStream(); | |
String sPostData = IOUtils.toString(inputStream, StandardCharsets.UTF_8); | |
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token,encodingaeskey,corpId); | |
String sMsg = wxcpt.DecryptMsg(sMsgSignature,sTimestamp,sNonce,sPostData); | |
//sMsg 是 xml 格式的字符串,我使用的是 hutool 工具下的插件转 map 的,你也可以用其它的方式 | |
Map<String, String> map = new HashMap<String, String>(10); | |
Document document = XmlUtil.parseXml(sMsg); | |
List<Element> xml = XmlUtil.getElements(document.getDocumentElement(), null); | |
for(Element x:xml){ | |
map.put(x.getTagName(),x.getTextContent()); | |
} | |
// 业务代码 ... | |
}catch (Exception e){ | |
logger.error("企业微信消息交互错误",e); | |
} | |
} | |
} |
# WXBizMsgCrypt 类下载
加解密库官方:下载地址 本文使用 JAVA 的下载地址
将文件全部拷贝到模块目录下用于引用
# 结束
文档很好很全面,这个配置一波过,就是只提供一个环境的消息服务器配置有点少。
# 2022/01/05 日 问题补充
# Last encoded character (before the paddings if any)
首先是我升级其它 jar 将 commons-codec 这个 jar 包版本升级到 1.14,导致企业微信提供的 WXBizMsgCrypt 类下 WXBizMsgCrypt 方法中的代码执行错误
// 报错代码 | |
aesKey = Base64.decodeBase64(encodingAesKey + "="); |
原因是在执行解密时调用 validateCharacter 方法,来验证在上下文中是否可以解码最后的尾随字符,而微信生成的 EncodingAESKey 无法通过校验。回退版本发现原来版本是 1.11。1.11 版本没有这个方法
# 解决办法
直接用当前 commons-codec 版本的加密方法加密一个 32 位的字符串。生成后得到 44 位的字符串去掉尾巴 = 字符串,得 43 位的字符串。它就是 EncodingAESKey 。再将这个 EncodingAESKey 替换微信随机生成的 EncodingAESKey 就可以了。
// 32 位字符串可以使用 UUID 去掉中间的 - 就剩下 32 位了 | |
Base64.encodeBase64String(UUID.randomUUID().toString().replaceAll("-","").getBytes()); |