1. 公众号开启并配置
2. Java代码实现
1. 验证加密工具类
package cn.com.baidu.wxopen.util.wx;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class WxSignUtil {
public static boolean checkSignature(String token, String signature, String timestamp, String nonce) {
String[] paramArr = new String[]{token, timestamp, nonce};
String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(content.getBytes());
checktext = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
return checktext != null && checktext.equals(signature.toUpperCase());
private static String byteToStr(byte[] byteArrays) {
for (int i = 0; i < byteArrays.length; i++) {
str += byteToHexStr(byteArrays[i]);
private static String byteToHexStr(byte myByte) {
char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char[] tampArr = new char[2];
tampArr[0] = Digit[(myByte >>> 4) & 0X0F];
tampArr[1] = Digit[myByte & 0X0F];
String str = new String(tampArr);
package cn.com.baidu.wxopen.util.wx;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
public class WXBizMsgCrypt {
static Charset CHARSET = Charset.forName("utf-8");
Base64 base64 = new Base64();
public WXBizMsgCrypt(String token, String encodingAesKey, String appId) throws AesException {
if (encodingAesKey.length() != 43) {
throw new AesException(AesException.IllegalAesKey);
aesKey = Base64.decodeBase64(encodingAesKey + "=");
byte[] getNetworkBytesOrder(int sourceNumber) {
byte[] orderBytes = new byte[4];
orderBytes[3] = (byte) (sourceNumber & 0xFF);
orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
int recoverNetworkBytesOrder(byte[] orderBytes) {
for (int i = 0; i < 4; i++) {
sourceNumber |= orderBytes[i] & 0xff;
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 16; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
String encrypt(String randomStr, String text) throws AesException {
ByteGroup byteCollector = new ByteGroup();
byte[] randomStrBytes = randomStr.getBytes(CHARSET);
byte[] textBytes = text.getBytes(CHARSET);
byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
byte[] appidBytes = appId.getBytes(CHARSET);
byteCollector.addBytes(randomStrBytes);
byteCollector.addBytes(networkBytesOrder);
byteCollector.addBytes(textBytes);
byteCollector.addBytes(appidBytes);
byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
byteCollector.addBytes(padBytes);
byte[] unencrypted = byteCollector.toBytes();
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte[] encrypted = cipher.doFinal(unencrypted);
String base64Encrypted = base64.encodeToString(encrypted);
throw new AesException(AesException.EncryptAESError);
String decrypt(String text) throws AesException {
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);
byte[] encrypted = Base64.decodeBase64(text);
original = cipher.doFinal(encrypted);
throw new AesException(AesException.DecryptAESError);
String xmlContent, from_appid;
byte[] bytes = PKCS7Encoder.decode(original);
byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
int xmlLength = recoverNetworkBytesOrder(networkOrder);
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
throw new AesException(AesException.IllegalBuffer);
if (!from_appid.equals(appId)) {
throw new AesException(AesException.ValidateAppidError);
public String encryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
String encrypt = encrypt(getRandomStr(), replyMsg);
timeStamp = Long.toString(System.currentTimeMillis());
String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);
String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
public String decryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
Object[] encrypt = XMLParse.extract(postData);
String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());
if (!signature.equals(msgSignature)) {
throw new AesException(AesException.ValidateSignatureError);
String result = decrypt(encrypt[1].toString());
public String verifyUrl(String msgSignature, String timeStamp, String nonce, String echoStr)
String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
if (!signature.equals(msgSignature)) {
throw new AesException(AesException.ValidateSignatureError);
String result = decrypt(echoStr);
2. 启用时的验证接口
@GetMapping("auth" + ISystemConstant.RELEASE_SUFFIX )
public void authGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
if (StringUtils.isNotBlank(request.getParameter("signature"))) {
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
if (WxSignUtil.checkSignature('你的Token', signature, timestamp, nonce)) {
response.getOutputStream().println(echostr);
3. 公众号事件触发接口
@PostMapping("auth" + ISystemConstant.RELEASE_SUFFIX )
public void authPost(HttpServletRequest request, HttpServletResponse response, PrintWriter pw) throws Exception{
WXBizMsgCrypt pc = new WXBizMsgCrypt("你的Token", "你的AesKey", "你的AppId");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String msgSignature = request.getParameter("msg_signature");
Document doc = getDocument(request);
String result2 = pc.decryptMsg(msgSignature, timestamp, nonce, doc.asXML());
Map map = docToMap(DocumentHelper.parseText(result2));
System.out.println("解密后明文: " + map);
String messageType = map.get("MsgType");
if(Objects.equals("event", messageType)) {
String event = map.get("Event");
if(Objects.equals(event, "subscribe")) {
String eventKey = map.get("EventKey");
String qrCodeParams = null;
if(eventKey != null && eventKey.length() > 0) {
System.out.println("二维码参数:" + eventKey.replaceFirst("qrscene_", ""));
qrCodeParams = eventKey.replaceFirst("qrscene_", "");
String message = "欢迎您的关注";
String openId = map.get("FromUserName");
String result = "" + " + map.get("FromUserName") + "]]>"
+ " + map.get("ToUserName") + "]]>" + ""
+ System.currentTimeMillis() + "" + ""
result = pc.encryptMsg(result, timestamp, nonce);
if(!StringUtils.isEmpty(qrCodeParams)) {
if(Objects.equals(event, "unsubscribe")) {
String openId = map.get("FromUserName");
System.out.println(openId + "取消了订阅");
if(Objects.equals(event, "SCAN")) {
String eventKey = map.get("EventKey");
String qrCodeParams = null;
if(eventKey != null && eventKey.length() > 0) {
System.out.println("二维码参数:" + eventKey.replaceFirst("qrscene_", ""));
qrCodeParams = eventKey.replaceFirst("qrscene_", "");
if(!StringUtils.isEmpty(qrCodeParams)) {
if(Objects.equals(event, "LOCATION")) {
String latitude = map.get("Latitude");
String longitude = map.get("Longitude");
String precision = map.get("Precision");
System.out.println(openId + "上报了位置:" + latitude + "," + longitude + "," + precision);
String msgType = map.get("MsgType");
if(msgType != null && msgType.equals("text")) {
String content = map.get("Content");
WxopenKeywordsDTO keywordsDTO = iWxopenKeywordsService.getQuery(content);
if(keywordsDTO != null) {
if (keywordsDTO.getKeywordsResultType().equals("1")) {
result = getXmlReturnMsg(map.get("FromUserName"), map.get("ToUserName"), keywordsDTO.getKeywordsResult());
if (keywordsDTO.getKeywordsResultType().equals("2")) {
result = getXmlReturnImageMsg(map.get("FromUserName"), map.get("ToUserName"), keywordsDTO.getKeywordsResultMediaId());
if (keywordsDTO.getKeywordsResultType().equals("6")) {
result = getXmlReturnImageMsg(map.get("FromUserName"), map.get("ToUserName"), keywordsDTO.getKeywordsTitle(), keywordsDTO.getKeywordsResult(), keywordsDTO.getKeywordsResultMediaUrl(), keywordsDTO.getKeywordsResultUrl());
result = pc.encryptMsg(result, timestamp, nonce);
response.setHeader("Content-type", "application/xml");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(result);
public String getXmlReturnMsg(String toUser, String fromUser, String content) {
" "+System.currentTimeMillis()+"\n" +
public String getXmlReturnImageMsg(String toUser, String fromUser, String title, String content, String mediaId, String url) {
" "+System.currentTimeMillis()+"\n" +
public String getXmlReturnImageMsg(String toUser, String fromUser, String mediaId) {
" "+System.currentTimeMillis()+"\n" +
public static Map docToMap(Document doc) {
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
List list = root.elements();
for (Element element : list) {
map.put(element.getName(), element.getText());
public static Document getDocument(HttpServletRequest request) {
SAXReader reader = new SAXReader();
InputStream ins = request.getInputStream();
Document doc = reader.read(ins);