java调用微信加密_java微信消息加解密

今天心血来潮就信手拈来学了下微信消息加解密的知识,忽然觉得微信真的好强大。可能在大部分项目微信消息的加解密都用不上,但是仍然不排除有使用到的情况,如涉及金钱方面的微信应用包括商城类、金融类还有其他安全级别要求很高的微信应用。针对这些情况我觉得还是有必要分享下我的学习心得。

一   功能概述

公众号消息加解密是公众平台为了进一步加强公众号安全保障,提供的新机制。开发者需注意,公众账号主动调用API的情况将不受影响。只有被动回复用户的消息时,才需要进行消息加解密。具体包括:

1.新增消息体签名验证,用于公众平台和公众账号验证消息体的正确性

2.针对推送给微信公众账号的普通消息和事件消息,以及推送给设备公众账号的设备消息进行加密

3.公众账号对密文消息的回复也要求加密 这段文字描述摘抄至微信公众平台开发者文档,从上面的描述可以看出消息加密旨在提高安全性。

二  公众平台如何设置消息加解密

点击左侧的开发者中心,找到相关的配置项即可,如下所示

89e9541a12a12b78707a776850dd77e1.png

三  编程实现

消息加解密支持的开发语言还是挺多的如java、C++、C#、php等,鉴于本人只懂java,因此代码部分将会全部使用java

1  有关消息加解密的关键代码

代码微信公众平台提供了下载链接,但是由于java开发环境的复杂性,直接使用微信提供的jar包会出现问题,因此不建议使用jar包而是直接使用源码,下面是用于加密的代码下载链接

2  代码编写之前的注意事项

(1)替换JCE策略文件

这主要是因为采用AES加密时,如果密钥长度大于128,会抛异常:java.security.InvalidKeyException: Illegal key size。下面是JCE的下载地址:

Java版本JCE无限制权限策略文件下载地址

1.8http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

1.7http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html

1.6http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

下载后替换%JDK_HOME%\jre\lib\security目录下对应的文件。

(2)使用微信提供的源代码

首先把zip解压缩,之后复制commons-codec这个jar包到项目,之后复制src下面的源代码粘贴到src下面

9c296913600b0306b05cc5b6ea54b224.png

3 微信消息加解密需调整的代码

(1) 新增处理用户请求消息的2组方法

public static WXBizMsgCrypt getWxCrypt() {

WXBizMsgCrypt crypt=null;

try {

crypt = new WXBizMsgCrypt(SignUtil.token,"xxxxx","xxxxx");

} catch (AesException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return crypt;

}这个方法用于取得微信消息加解密的实例

public static Map parseXmlCrypt(HttpServletRequest request) throws Exception {

// 将解析结果存储在HashMap中

Map map = new HashMap();

// 从request中取得输入流

InputStream inputStream = request.getInputStream();

BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream));

String line;

StringBuffer buf=new StringBuffer();

while((line=reader.readLine())!=null){

buf.append(line);

}

reader.close();

inputStream.close();

WXBizMsgCrypt wxCeypt=MessageUtil.getWxCrypt();

// 微信加密签名

String msgSignature = request.getParameter("msg_signature");

// 时间戳

String timestamp = request.getParameter("timestamp");

// 随机数

String nonce = request.getParameter("nonce");

String respXml=wxCeypt.decryptMsg(msgSignature, timestamp, nonce, buf.toString());

//SAXReader reader = new SAXReader();

Document document =DocumentHelper.parseText(respXml);

// 得到xml根元素

Element root = document.getRootElement();

// 得到根元素的所有子节点

List elementList = root.elements();

// 遍历所有子节点

for (Element e : elementList)

map.put(e.getName(), e.getText());

// 释放资源

//inputStream.close();

//inputStream = null;

return map;

}

该方法主要用于把用户发来的消息进行解密处理

/*

* 微信控制器(入口)

*/

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

// 将请求、响应的编码均设置为UTF-8(防止中文乱码)

request.setCharacterEncoding("UTF-8");

response.setCharacterEncoding("UTF-8");

String encryptType = request.getParameter("encrypt_type");

// 微信加密签名

String signature = request.getParameter("signature");

// 时间戳

String timestamp = request.getParameter("timestamp");

// 随机数

String nonce = request.getParameter("nonce");

// 响应消息

try{

PrintWriter out = response.getWriter();

if (SignUtil.checkSignature(signature, timestamp, nonce)) {

Map requestMap = null;

if("aes".equals(encryptType)){

requestMap=MessageUtil.parseXmlCrypt(request);

String respXml=CoreService.processRequest(requestMap);

respXml=MessageUtil.getWxCrypt().encryptMsg(respXml,timestamp,nonce);

System.out.println(respXml);

out.print(respXml);

}else{

requestMap=MessageUtil.parseXml(request);

String respXml=CoreService.processRequest(requestMap);

//respXml=MessageUtil.getWxCrypt().encryptMsg(respXml,timestamp,nonce);

out.print(respXml);

System.out.println(respXml);

}

// 调用核心业务类接收消息、处理消息

//String respMessage = CoreService.processRequest(request);

out.close();

}

}catch(Exception e){

e.printStackTrace();

}

}

相比之前的代码加了一个encrypt_type,为了考虑程序的健壮性,程序根据encrypt_type的值进行了判断,使得程序同时支持消息的明文模式和安全模式,同时CoreService里的方法也进行了一定的调整(主要体现在参数上面)

package com.debug.weixin.service;

import java.util.Date;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.debug.weixin.message.res.CustomServiceMessage;

import com.debug.weixin.message.res.TextMessage;

import com.debug.weixin.pojo.TransInfo;

import com.debug.weixin.util.MessageUtil;

public class CoreService {

/**

* 处理微信发来的请求

*

* @param request

* @return

*/

public static String processRequest( Map requestMap) {

String respMessage = null;

TextMessage tm=null;

try {

// 默认返回的文本消息内容

String respContent = "请求处理异常,请稍候尝试!";

// xml请求解析

//Map requestMap = MessageUtil.parseXml(request);

// 发送方帐号(open_id)

String fromUserName = requestMap.get("FromUserName");

// 公众帐号

String toUserName = requestMap.get("ToUserName");

// 消息类型

String msgType = requestMap.get("MsgType");

// 回复文本消息

tm= new TextMessage();

tm.setToUserName(fromUserName);

tm.setFromUserName(toUserName);

tm.setCreateTime(new Date().getTime());

tm.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);

System.out.println("msgType:"+msgType);

// 文本消息

if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {

String content=requestMap.get("Content");

if(content.startsWith("人工客服")){

CustomServiceMessage cus=new CustomServiceMessage();

cus.setToUserName(fromUserName);

cus.setFromUserName(toUserName);

cus.setCreateTime(new Date().getTime());

cus.setMsgType(MessageUtil.TRANSFER_CUSTOMER_SERVICE);

TransInfo t=new TransInfo();

t.setKfAccount("debug@php-wechat-crm");

cus.setTransInfo(t);

respMessage=MessageUtil.customMessageToXml(cus);

}else{

respContent = "您发送的是文本消息!";

}

}

// 图片消息

else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {

respContent = "您发送的是图片消息!";

}

// 地理位置消息

else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {

respContent = "您发送的是地理位置消息!";

}

// 链接消息

else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {

respContent = "您发送的是链接消息!";

}

// 音频消息

else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {

respContent = "您发送的是音频消息!";

}

// 事件推送

else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {

// 事件类型

String eventType = requestMap.get("Event");

// 订阅

if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {

String ticket=requestMap.get("Ticket");

if(ticket!=null&&!"".equals(ticket)){

respContent="谢谢您的关注!,你的ticket是:"+ticket;

}else{

respContent="谢谢您的关注!";

}

}

// 取消订阅

else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {

// TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息

}

// 自定义菜单点击事件

else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {

// TODO 自定义菜单权没有开放,暂不处理该类消息

String eventKey=requestMap.get("EventKey");

if("language".equalsIgnoreCase(eventKey.trim())){

}

}else if(eventType.equals("SCAN")){

String eventKey=requestMap.get("EventKey");

String ticket=requestMap.get("Ticket");

respContent="你的ticket是:"+ticket;

}

}

tm.setContent(respContent);

//respMessage = MessageUtil.textMessageToXml(textMessage);

} catch (Exception e) {

e.printStackTrace();

}

if(respMessage==null){

return MessageUtil.textMessageToXml(tm);

}else{

return respMessage;

}

//return respMessage;

}

}

bcbd001bc303b718dd92b50992530e60.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值