java调用微信加密_用spring搭建微信公众号开发者模式下服务器处理用户消息的加密传输构架(java)...
要搭建加密传输的微信公众号消息传输,首先要在开发这平台下载一下微信加密的相关jar包,并做一些准备。准备的步骤如下:
1.打开开发者文档,找到消息加减密--->接入指引,如下图所示:
2.在页面底部找到实例代码,并下载解压,下载的地方如下图所示:
3.在解压的地方找到java版本,并做如下准备:
(1)将commons-codec-1.9.jar导入到项目中。
(2)将dist下的aes-jre1.6.jar导入到项目中。
(3)打开readme.txt,按照他的指示操作。红色对勾的地方很重要。
要下载的东西就是下图标记的地方
这样准备工作就完成了,可以进入正式的代码编写了。
代码部分的解释基本都放在注释中,首先开用来核心控制的controller。内容如下:
package org.calonlan.soulpower.controller;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.calonlan.soulpower.service.WeiInfoService;
import org.calonlan.soulpower.util.AesUtils;
import org.calonlan.soulpower.util.MessageUtil;
import org.calonlan.soulpower.util.SignUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author Administrator
* 这个controller是用来处理消息的核心controller,在这里有两个请求地址都为/sign的请求地址,一个是用get方式,用来
* 做服务器和微信服务器之间的认证;一个是post方式,用来在服务器和微信服务器之间传递消息。
*/
@Controller
@RequestMapping("/core")
public class CoreController {
@Resource
private WeiInfoService weiInfoService;/*
* 这个service大家可以不用管,
* 因为在我的项目中我是把所有的微信相关的配置信息都保存在一个weiInfo的类中了
* ,这里只会用到token。
*/
/**
* @param request
* @param response
* @throws IOException
* @throws ServletException
* 用来和微信服务器之间相互认证
*/
@RequestMapping(method = RequestMethod.GET, value = "/sign")
public void goGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String signature = request.getParameter("signature");// 获得signature
String timestamp = request.getParameter("timestamp");// 获得timestamp
String nonce = request.getParameter("nonce");// 获得nonce
String echostr = request.getParameter("echostr");// 获得echostr
/*
* 上面的四个参数都是微信服务器发送过来的,其中signature、timestamp、nonce是要参与服务器的验证的,
* 而echostr是在我们通过验证后返回给服务器告诉服务器我们就是要通讯 的那个远程服务器
*/
PrintWriter out = response.getWriter();
if (SignUtil.checkSignature(signature, timestamp, nonce,
weiInfoService.get())) {//在SignUtil中使用checkSignature来进行验证,代码附在后面。
out.print(echostr);//验证通过后就把echostr返回给微信服务器。
}
out.close();
out = null;
}
@RequestMapping(method = RequestMethod.POST, value = "/sign")
/**
*
* 用来和微信服务器通信
*
* */
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
/** 进行消息分发 */
/* 首先定义一个空的回复消息 */
String respMessage = "";
try {
/* 从请求中获得xml格式的信息。并转化为map类型 */
Map requestMapSecret = MessageUtil
.parseXml(request);//从request中获得获得xml,并解析,代码附在后面
/* 获得解密后的消息正文 */
String mingwenXML = AesUtils.descMessage(//用微信官方给的jar包中的AesUtils来对消息进行解密
requestMapSecret.get("Encrypt"),/* 加密的消息体 */
request.getParameter("msg_signature"),/* 请求中的消息签名 */
request.getParameter("timestamp"),/* 时间戳 */
request.getParameter("nonce"));/* 无序数列 */
/* 将明文再次进行xml解析 */
Map requestMap = MessageUtil
.parseXml(new StringReader(mingwenXML));//将明文的xml再次解析后放入map中,
/** 获得用户发来的消息类型,并做相应的处理 */
String messageType = requestMap.get("MsgType");
System.out.println(messageType);
/*处理不同格式的消息类型开始-------------------------------------------------------*/
// 用户发来的是文本消息
if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
System.out.println(requestMap.get("Content"));
}
// 用户发来的是图片消息
else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
}
// 用户发来地理位置信息
else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
}
// 用户发来链接消息
else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
}
// 用户发来音频消息
else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
}
/** 事件推送的处理 */
else if (messageType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType = requestMap.get("Event");
// 订阅
if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_SUBSCRIBE)) {
}
// 取消订阅
else if (eventType
.equals(MessageUtil.REQ_MESSAGE_TYPE_UNSUBSCRIBE)) {
}
// 点击按钮事件
else if (eventType.equals(MessageUtil.REQ_MESSAGE_TYPE_CLICK)) {
}
}
/*处理不同格式的消息类型介绍-------------------------------------------------------*/
/*对于不同类型的消息的处理网上有很多高手已经发表了很多文章了,我自己也会总结一下,不过不是在这里---------*/
// 给返回的消息加密
AesUtils.aescMessage(respMessage,
request.getParameter("timestamp"),
request.getParameter("nonce"));
} catch (Exception e) {
e.printStackTrace();
}
/*返回消息给微信服务器,然后微信服务器把消息转发给用户···额,貌似我们聊什么,微信服务器都是可以截获的,*/
PrintWriter out = response.getWriter();
out.print(respMessage);
out.close();
}
}
SignUtil中的checkSignature代码如下:
public static boolean checkSignature(String signature, String timestamp,
String nonce, WeiInfo info) {
/*
* 微信服务器发送过来的signature是通过某些处理然后进行SHA1加密的,我们来用它发过来的信息自己生成一个signature,
* 然后两者之间进行比对,一致的话我们就是伙伴,不一致就拒绝它
*/
String[] arr = new String[] { info.getToken(), timestamp, nonce };
/* token是我们自己填写的,具体填写位置见下图;timestamp、nonce是微信服务器发送过来的,这里我们把他们都放到数组中。*/
Arrays.sort(arr);//对数组中的数据进行字典排序。。。。要不然加密出来的东西是没用的
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}//把字典排序好的数组读取成字符串。
MessageDigest md = null;
String tmpStr = null;
try {/*进行sha1加密*/
md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);//将加密后的byte转化为16进制字符串,这就是我们自己构造的signature
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = null;
return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;//进行对比,相同返回true,不同返回false
}
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);//分别把没一个byte位转换成一个16进制字符,代码见下面
}
return strDigest;
}
private static String byteToHexStr(byte mByte) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
AesUtils的具体代码
package org.calonlan.soulpower.util;
import org.calonlan.soulpower.dao.impl.WeiInfoDaoImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AesUtils {
private static ApplicationContext applicationContext;
/*
* 这里我直接使用的spring来读取weiInfo对象中的加解密密钥的内容,大家可以不用这样,直接把密钥放在这里就可以了,
* 也可以放在properties文件中读取更方便
*/
public static String descMessage(String encrypt, String msgSignature,
String timestamp, String nonce) throws AesException {
applicationContext = new ClassPathXmlApplicationContext(
"config/application-context.xml");
WeiInfoDaoImpl daoImpl = (WeiInfoDaoImpl) applicationContext
.getBean("weiInfoDao");
String token = daoImpl.get().getToken();//获得token
String encodingAesKey = daoImpl.get().getEncodingAesKey();//获得加解密密钥
String appId = daoImpl.get().getAppId();//获得appid,这个在开发者模式下就能看到,填写你自己的。
String format = "";
String fromXML = String.format(format, encrypt);
WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
String result = pc.decryptMsg(msgSignature, timestamp, nonce, fromXML);
return result;
}
/*加密和解密类似,就不做注释了*/
public static String aescMessage(String replyMsg, String timestamp,
String nonce) throws AesException {
applicationContext = new ClassPathXmlApplicationContext(
"config/application-context.xml");
WeiInfoDaoImpl daoImpl = (WeiInfoDaoImpl) applicationContext
.getBean("weiInfoDao");
String token = daoImpl.get().getToken();
String encodingAesKey = daoImpl.get().getEncodingAesKey();
String appId = daoImpl.get().getAppId();
WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
String mingwen = pc.encryptMsg(replyMsg, timestamp, nonce);
return mingwen;
}
}
MessageUtil中的parseXml代码,有两个,一个是用来直接解析request中的xml,一个是用来解析字符串类型的xml
解析request中的xml代码
public static Map parseXml(HttpServletRequest request)
throws Exception {
Map map = new HashMap();
InputStream inputStream = request.getInputStream();
SAXReader reader = new SAXReader();//我用的是SAXReader
Document document = reader.read(inputStream);
Element root = document.getRootElement();
@SuppressWarnings("unchecked")
List elementList = root.elements();
for (Element e : elementList) {
map.put(e.getName(), e.getText());
}
inputStream.close();
inputStream = null;
return map;
}
解析字符串中的xml代码
public static Map parseXml(StringReader readers) {
Map map = new HashMap();
SAXReader reader = new SAXReader();
Document document = null;
try {
InputSource inputSource = new InputSource(readers);
document = reader.read(inputSource);
} catch (DocumentException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Element root = document.getRootElement();
@SuppressWarnings("unchecked")
List elementList = root.elements();
for (Element e : elementList) {
map.put(e.getName(), e.getText());
}
return map;
}
到这里,构建就完成了,可以用我们的服务器来和微信服务器进行密文的消息传递了。
java调用微信加密_用spring搭建微信公众号开发者模式下服务器处理用户消息的加密传输构架(java)...相关推荐
- 用spring搭建微信公众号开发者模式下服务器处理用户消息的加密传输构架(java)
要搭建加密传输的微信公众号消息传输,首先要在开发这平台下载一下微信加密的相关jar包,并做一些准备.准备的步骤如下: 1.打开开发者文档,找到消息加减密--->接入指引,如下图所示: 2.在页面 ...
- 微信开发者模式php,php 开启微信公众号开发者模式
php 开启微信公众号开发者模式 /** * wechat php test */ header('Content-type:text'); //define your token //定义TOKEN ...
- 微信公众号基本设置服务器设置教程,最新最全的微信公众号开发者模式配置
微信公众号的开发分为编辑模式和开发者模式,那么最新最全的微信公众号开发者模式配置是什么呢,下面是学习啦小编收集整理的最新最全的微信公众号开发者模式配置,希望对大家有帮助~~ 最新最全的微信公众号开发者 ...
- 微信开发者模式php,PHP实现模拟微信公众号开发者模式
本文主要和大家分享PHP实现模拟微信公众号开发者模式,主要以代码的形式和大家分享,希望能帮助到大家.$url = 'http://xxxx.com/test/aaaa/index.php';//开发者 ...
- 微信公众号开发者模式菜单不更新的问题
这个问题困扰了我好几天,度娘到的都是24小时内,然而到了24小时并没有什么卵用. 开发者模式下,后台的菜单信息更新后,微信服务器并没有来拉取菜单数据,所以我们自己动手让它来拉取菜单信息. 官方debu ...
- 登录用友显示java已被阻止_解决Spring Security 用户帐号已被锁定问题
1.问题描述 主要就是org.springframework.security.authentication.LockedException: 用户帐号已被锁定这个异常,完整异常如下: [2020-0 ...
- 微信公众号开发者模式回复信息带表情(QQ,emoji)
最近做微信公众号的迭代 老板非要发送消息带表情 我调研了网上的各种方法 各种开源代码和项目经验 没一个能用的- o(╥﹏╥)o emoji 下面是整个流程 首先,我自己测试,先往公众号发表情,后台去接 ...
- 微信服务号开发者模式下 自定义创建菜单,跳转到其他url
首先看服务号下面配置信息,表示开发者模式已经打开. 这个时候,进入服务号查看,菜单已经消失. 接下来就是我们今天的主要内容,通过官方提供的调试工具,创建菜单. 当然,你也可以手写请求过程,第一步获取A ...
- 什么是php微信开发,php微信公众号开发模式详解
这篇文章主要介绍了php微信公众号开发者模式,通过后台服务器与微信关注用户实现更多的交互作用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 学习步骤:分四章来讲述这部分内容,下面是每章的大致内容. ...
最新文章
- python相关函数_python常用函数精讲
- WinAPI: CreateDirectoryEx - 根据模版建立文件夹
- 安全挑战和SD-WAN解决方案
- GPS系统跟踪捕获算法的Verilog实现
- 吴恩达《神经网络与深度学习》精炼笔记(4)-- 浅层神经网络
- uniapp下载文件保存到手机本地
- 浅谈算法和数据结构: 十一 哈希表
- ec12编码器电路图_光电编码器的电路原理图详解
- 一个不用背单词的高效英文学习法
- SQL练习题附重点函数说明--更新至21题
- jQuery-WEUI的Uploader实现上传多张图片并且限制上传数量的方法
- java开发linux常用命令
- Android 电子签名
- 机器学习苹果识别——python+opencv实现物体特征提取
- GhostNet网络详解
- python安装方法32位_python安装教程
- 数字化引领LED照明的未来
- A_A02_003 ST-LINK驱动安装
- android studio 视屏播放器 MediaController
- 图解基于node.js实现前后端分离
热门文章
- 想被千年后的人知道吗,快去GitHub上传代码吧!
- Python日志模块学习,从这里开始...
- 直播课:5G来了,互联网百亿级创新的机遇在哪里?
- Python爬取Boss直聘,帮你获取全国各类职业薪酬榜
- 【Python3网络爬虫开发实战】1.2.4-GeckoDriver的安装
- 邢台学计算机的技校有哪些,邢台技校有哪些,邢台技校排名
- mysql 结果集 超大_使用MySQL流式传输大型结果集
- 华为修改优先级命令_(完整版)华为设备基本配置命令
- 扩展、统计线性化和无迹RTS平滑器
- 零门槛人像转卡通、GIF表情包(赶快行动起来)