welcome to xlongwei.com

欢迎大家一起学习、交流、分享


QQ:9167702333 邮箱:admin@xlongwei.com

微信公众号消息加密解密


分类 Java   关键字 分享   标签 java   algorithm   发布 hongwei  1464582730094
注意 转载须保留原文链接,译文链接,作者译者等信息。  
微信公众号消息支持AES加密传输,从而可以更好地保护用户数据。参考微信公众号开发文档,需要更新JCE无限制权限策略文件,同时还有引入weixin提供的jar包。

更新JCE无限制权限策略文件和引入微信加密解密jar包
http://tool.xlongwei.com/softwares/jce_policy-JDK7.zip  #还有JDK6和JDK8版本
http://nexus.xlongwei.com/content/groups/public/com/qq/weixin/mp/aes/1.6/aes-1.6.jar
<dependency>
<groupId>com.qq.weixin.mp</groupId>
<artifactId>aes</artifactId>
<version>1.6</version>
</dependency>

封装加密解密方法,见WeixinUtil
private static final Map<String, WXBizMsgCrypt> wxBizMsgCrypts = new HashMap<>();
//支持配置一次appId,后续加密解密都不需要token和encodingAesKey参数了
public static void configAES(String appId, String token, String encodingAesKey) {
try {
wxBizMsgCrypts.put(appId, new WXBizMsgCrypt(token, encodingAesKey, appId));
}catch(Exception e) {
logger.warn(e.getMessage());
}
}

public static String encrypt(String appId, String replyMsg, String timestamp, String nonce) {
try {
WXBizMsgCrypt pc = wxBizMsgCrypts.get(appId);
return pc==null ? null : pc.encryptMsg(replyMsg, timestamp, nonce);
} catch (AesException e) {
logger.warn(e.getMessage());
}
return null;
}
public static String decrypt(String appId, String msgSignature, String timestamp, String nonce, String fromXML) {
try {
WXBizMsgCrypt pc = wxBizMsgCrypts.get(appId);
return pc==null ? null : pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);
} catch (AesException e) {
logger.warn(e.getMessage());
}
return null;
}

微信公众号后台开启安全模式后,将会收到加密消息,因此需要先解密,然后再交给MessageDispatcher处理,得到响应消息后,还需要加密,再返回给微信,见CallbackController
String xml = FileUtil.readString(request.getInputStream(), FileUtil.CharsetNames.UTF_8);
logger.info(xml);//请求正文才是消息或密文
String appid = GlobalConfig.getProperty("weixin.appId");
String timestamp = RequestUtil.getStringParam(request, "timestamp", null);//请求参数用于校验
String nonce = RequestUtil.getStringParam(request, "nonce", null);
boolean aes = "aes".equals(RequestUtil.getStringParam(request, "encrypt_type", null));//可能为空、raw、aes
if(aes) {
String msgSignature = RequestUtil.getStringParam(request, "msg_signature", null);
String decrypt = WeixinUtil.decrypt(appid, msgSignature, timestamp, nonce, xml);//解密出明文消息
logger.info("decrypt: "+decrypt);
xml = decrypt;
}
Message msg = Message.fromXML(xml);
msg = msg == null ? null : messageDispatcher.dispatch(msg);
xml = msg !=null ? msg.toXML() : "";
logger.info(xml);
if(aes && !StringUtil.isBlank(xml)) {
String encrypt = WeixinUtil.encrypt(appid, xml, timestamp, nonce);//加密成密文消息,这里复用了timestamp和nonce参数
logger.info("encrypt: "+encrypt);
xml = encrypt;
}
return xml;

自己实现还是比较麻烦的,更简便的方法时调用微信公众号接口参考文档
接口参数与以下函数参数一致:
解密:WeixinUtil.decrypt(appid, msgSignature, timestamp, nonce, xml)
加密:WeixinUtil.encrypt(appid, xml, timestamp, nonce),首次调用解密时额外传入token和encodingAesKey即可。