java微信企业号开发之开发模式的开启
作者:ggibenben1314 发布时间:2022-03-20 10:58:02
标签:java,微信,企业号,开发模式
首先说微信企业号的开发模式分为:编辑模式(普通模式)和开发模式(回调模式) ,在编辑模式下,只能做简单的自定义菜单和自动回复消息,要想实现其他功能还得开启开发者模式。
一、编辑模式和开发模式对消息的处理流程
1.编辑模式下,所有的业务流程都配置在微信服务器上,由它处理
2.开发模式,消息通过第三方服务器处理,最后经过微信服务器把消息发送给用户
开发模式能处理的消息比编辑模式多,所以要先开启开发模式才能开发更多功能。
二、开发模式的开启
在回调模式下,企业不仅可以主动调用企业号接口,还可以接收用户的消息或事件。接收的信息使用XML数据格式、UTF8编码,并以AES方式加密。
1.开启回调模式后要配置参数如下:
其中url是要访问的servlet,token和EncodingAESKey是随机获取的,但要和项目中保持一致。
2.验证URL的有效性
当你提交以上信息时,企业号将发送GET请求到填写的URL上,GET请求携带四个参数,企业在获取时需要做urldecode处理,否则会验证不成功。
3.代码
CoreServlet1类
public class CoreServlet1 extends HttpServlet {
private static final long serialVersionUID = 4440739483644821986L;
String sToken = "weixinCourse";
String sCorpID = "wxe510946434680dab";
String sEncodingAESKey = "DjlyZxgKiWRESIW2VnV9dSr7HsS7usWDfnwA8Q1ove1";
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
WXBizMsgCrypt wxcpt;
try {
wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
String sVerifyMsgSig = request.getParameter("msg_signature");
String sVerifyTimeStamp = request.getParameter("timestamp");
String sVerifyNonce = request.getParameter("nonce");
String sVerifyEchoStr = request.getParameter("echostr");
String sEchoStr;
sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,
sVerifyNonce, sVerifyEchoStr);
System.out.println("verifyurl echostr: " + sEchoStr);
PrintWriter out = response.getWriter();
out.print(sEchoStr);
out.close();
out = null;
} catch (AesException e1) {
e1.printStackTrace();
}
}
}
工具类:
/**
* 对公众平台发送给公众账号的消息加解密示例代码.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
// ------------------------------------------------------------------------
/**
* 针对org.apache.commons.codec.binary.Base64,
* 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
* 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
*/
package com.qq.weixin.mp.aes;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
* 提供接收和推送给公众平台消息的加解密接口(UTF8编码的字符串).
* <ol>
* <li>第三方回复加密消息给公众平台</li>
* <li>第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。</li>
* </ol>
* 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案
* <ol>
* <li>在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:
* http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html</li>
* <li>下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt</li>
* <li>如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件</li>
* <li>如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件</li>
* </ol>
*/
public class WXBizMsgCrypt {
static Charset CHARSET = Charset.forName("utf-8");
Base64 base64 = new Base64();
byte[] aesKey;
String token;
String corpId;
/**
* 构造函数
* @param token 公众平台上,开发者设置的token
* @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey
* @param corpId 企业的corpid
*
* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
*/
public WXBizMsgCrypt(String token, String encodingAesKey, String corpId) throws AesException {
if (encodingAesKey.length() != 43) {
throw new AesException(AesException.IllegalAesKey);
}
this.token = token;
this.corpId = corpId;
aesKey = Base64.decodeBase64(encodingAesKey + "=");
}
/**
* 对密文进行解密.
*
* @param text 需要解密的密文
* @return 解密得到的明文
* @throws AesException aes解密失败
*/
String decrypt(String text) throws AesException {
byte[] original;
try {
// 设置解密模式为AES的CBC模式
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
// 使用BASE64对密文进行解码
byte[] encrypted = Base64.decodeBase64(text);
// 解密
original = cipher.doFinal(encrypted);
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.DecryptAESError);
}
String xmlContent, from_corpid;
try {
// 去除补位字符
byte[] bytes = PKCS7Encoder.decode(original);
// 分离16位随机字符串,网络字节序和corpId
byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
int xmlLength = recoverNetworkBytesOrder(networkOrder);
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
from_corpid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
CHARSET);
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.IllegalBuffer);
}
// corpid不相同的情况
if (!from_corpid.equals(corpId)) {
throw new AesException(AesException.ValidateCorpidError);
}
return xmlContent;
}
/**
* 验证URL
* @param msgSignature 签名串,对应URL参数的msg_signature
* @param timeStamp 时间戳,对应URL参数的timestamp
* @param nonce 随机串,对应URL参数的nonce
* @param echoStr 随机串,对应URL参数的echostr
*
* @return 解密之后的echostr
* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
*/
public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
throws AesException {
String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
if (!signature.equals(msgSignature)) {
throw new AesException(AesException.ValidateSignatureError);
}
String result = decrypt(echoStr);
return result;
}
}
/**
* 对公众平台发送给公众账号的消息加解密示例代码.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
// ------------------------------------------------------------------------
package com.qq.weixin.mp.aes;
import java.security.MessageDigest;
import java.util.Arrays;
/**
* SHA1 class
*
* 计算公众平台的消息签名接口.
*/
class SHA1 {
/**
* 用SHA1算法生成安全签名
* @param token 票据
* @param timestamp 时间戳
* @param nonce 随机字符串
* @param encrypt 密文
* @return 安全签名
* @throws AesException
*/
public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
{
try {
String[] array = new String[] { token, timestamp, nonce, encrypt };
StringBuffer sb = new StringBuffer();
// 字符串排序
Arrays.sort(array);
for (int i = 0; i < 4; i++) {
sb.append(array[i]);
}
String str = sb.toString();
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.ComputeSignatureError);
}
}
}
class PKCS7Encoder {
static Charset CHARSET = Charset.forName("utf-8");
static int BLOCK_SIZE = 32;
/**
* 删除解密后明文的补位字符
*
* @param decrypted 解密后的明文
* @return 删除补位字符后的明文
*/
static byte[] decode(byte[] decrypted) {
int pad = (int) decrypted[decrypted.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
}
}
三、总结
企业通过参数msg_signature对请求进行校验,如果确认此次GET请求来自企业号,那么企业应用对echostr参数解密并原样返回echostr明文(不能加引号),则接入验证生效,回调模式才能开启。开启后一些功能会陆续实现,敬请期待!


猜你喜欢
- spring boot 使用POI读取Excel文件Excel文件目录Excel模板文件存了resourse目录下,如下图:<depe
- 本文实例讲述了C++实现的O(n)复杂度内查找第K大数算法。分享给大家供大家参考,具体如下:题目:是在一组数组(数组元素为整数,可正可负可为
- 1、前言 最近做项目需要用到监测网速及流量,我经过百度和墙内谷歌都没能快速发现监测IPV6流量和网速的用例;也经过自己的一番查询和调试,浪
- 1、导包,四大核心包,一个切面包(AOP),logging,web,springmvc2、配置文件,核心代码如下:web.xml<se
- 本文实例讲述了Java实现打印二叉树所有路径的方法。分享给大家供大家参考,具体如下:问题:给一个二叉树,把所有的路径都打印出来。比如,对于下
- 发布:一个对象是使它能够被当前范围之外的代码所引用:常见形式:将对象的的引用存储到公共静态域;非私有方法中返回引用;发布内部类实例,包含引用
- 抽象类往往用来表征对问题领域进行分析、设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。下面我们以水果为例,首先定
- 前言Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其
- 引言热修复技术如今已经不是一个新颖的技术,很多公司都在用,而且像阿里、腾讯等互联网巨头都有自己的热修复框架,像阿里的AndFix采用的是ho
- 固定的策略有时候还是无法满足千变万化的需求变动,一方面需要支持特定的用户需求,另一方面又得尽可能的复用代码,避免重复开发,这就需要将这部分的
- 基于 springboot+vue 的测试平台(练手项目)开发继续更新。在接口编辑页中点击发送接口请求,除了显示响应体外,还可以显示响应头等
- 前言使用输入框时产品常常会有一些需求,比如123456789变成123-456-789或者限制一些字符的输入等等。很多时候都是网上搜索就完事
- Android动态修改ToolBar的Menu菜单效果图实现实现很简单,就是一个具有3个Action的Menu,在我们滑动到不同状态的时候,
- 一、创建地形1、GameObject ->3D Object-> Terrain,创建带有地形属性的平面2、Terrain-〉最
- 前言BeanPostProcessor 接口定义了一个你可以自己实现的回调方法,来实现你自己的实例化逻辑、依赖解决逻辑等,如果你想要在Spr
- Java提供一种机制叫做序列化,通过有序的格式或者字节序列持久化java对象,其中包含对象的数据,还有对象的类型,和保存在对象中
- Java把内存分成两种,一种叫做栈内存,一种叫做堆内存在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。
- Java 8 lambda表达式引入详解及实例eclipse下载安装Help -> EclipseMarketplace ->
- 最近制作了一个多屏幕的项目,多屏幕指的是一个电脑主机,连接多个显示器。我这个项目使用了一个显卡连接了三个显示设备。Unity UGUI提供C
- 适合人群学完Java基础想通过Java快速构建web应用程序想学习或了解SpringBoot背景本节给大家讲讲 Java的Spri