java微信企業(yè)號(hào)開發(fā)之開發(fā)模式的開啟
首先說(shuō)微信企業(yè)號(hào)的開發(fā)模式分為:編輯模式(普通模式)和開發(fā)模式(回調(diào)模式) ,在編輯模式下,只能做簡(jiǎn)單的自定義菜單和自動(dòng)回復(fù)消息,要想實(shí)現(xiàn)其他功能還得開啟開發(fā)者模式。
一、編輯模式和開發(fā)模式對(duì)消息的處理流程
1.編輯模式下,所有的業(yè)務(wù)流程都配置在微信服務(wù)器上,由它處理

2.開發(fā)模式,消息通過(guò)第三方服務(wù)器處理,最后經(jīng)過(guò)微信服務(wù)器把消息發(fā)送給用戶

開發(fā)模式能處理的消息比編輯模式多,所以要先開啟開發(fā)模式才能開發(fā)更多功能。
二、開發(fā)模式的開啟
在回調(diào)模式下,企業(yè)不僅可以主動(dòng)調(diào)用企業(yè)號(hào)接口,還可以接收用戶的消息或事件。接收的信息使用XML數(shù)據(jù)格式、UTF8編碼,并以AES方式加密。
1.開啟回調(diào)模式后要配置參數(shù)如下:

其中url是要訪問(wèn)的servlet,token和EncodingAESKey是隨機(jī)獲取的,但要和項(xiàng)目中保持一致。
2.驗(yàn)證URL的有效性
當(dāng)你提交以上信息時(shí),企業(yè)號(hào)將發(fā)送GET請(qǐng)求到填寫的URL上,GET請(qǐng)求攜帶四個(gè)參數(shù),企業(yè)在獲取時(shí)需要做urldecode處理,否則會(huì)驗(yàn)證不成功。

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();
}
}
}
工具類:
/**
* 對(duì)公眾平臺(tái)發(fā)送給公眾賬號(hào)的消息加解密示例代碼.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
// ------------------------------------------------------------------------
/**
* 針對(duì)org.apache.commons.codec.binary.Base64,
* 需要導(dǎo)入架包c(diǎn)ommons-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;
/**
* 提供接收和推送給公眾平臺(tái)消息的加解密接口(UTF8編碼的字符串).
* <ol>
* <li>第三方回復(fù)加密消息給公眾平臺(tái)</li>
* <li>第三方收到公眾平臺(tái)發(fā)送的消息,驗(yàn)證消息的安全性,并對(duì)消息進(jìn)行解密。</li>
* </ol>
* 說(shuō)明:異常java.security.InvalidKeyException:illegal Key Size的解決方案
* <ol>
* <li>在官方網(wǎng)站下載JCE無(wú)限制權(quán)限策略文件(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,將兩個(gè)jar文件放到%JRE_HOME%\lib\security目錄下覆蓋原來(lái)的文件</li>
* <li>如果安裝了JDK,將兩個(gè)jar文件放到%JDK_HOME%\jre\lib\security目錄下覆蓋原來(lái)文件</li>
* </ol>
*/
public class WXBizMsgCrypt {
static Charset CHARSET = Charset.forName("utf-8");
Base64 base64 = new Base64();
byte[] aesKey;
String token;
String corpId;
/**
* 構(gòu)造函數(shù)
* @param token 公眾平臺(tái)上,開發(fā)者設(shè)置的token
* @param encodingAesKey 公眾平臺(tái)上,開發(fā)者設(shè)置的EncodingAESKey
* @param corpId 企業(yè)的corpid
*
* @throws AesException 執(zhí)行失敗,請(qǐng)查看該異常的錯(cuò)誤碼和具體的錯(cuò)誤信息
*/
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 + "=");
}
/**
* 對(duì)密文進(jìn)行解密.
*
* @param text 需要解密的密文
* @return 解密得到的明文
* @throws AesException aes解密失敗
*/
String decrypt(String text) throws AesException {
byte[] original;
try {
// 設(shè)置解密模式為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對(duì)密文進(jìn)行解碼
byte[] encrypted = Base64.decodeBase64(text);
// 解密
original = cipher.doFinal(encrypted);
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.DecryptAESError);
}
String xmlContent, from_corpid;
try {
// 去除補(bǔ)位字符
byte[] bytes = PKCS7Encoder.decode(original);
// 分離16位隨機(jī)字符串,網(wǎng)絡(luò)字節(jié)序和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;
}
/**
* 驗(yàn)證URL
* @param msgSignature 簽名串,對(duì)應(yīng)URL參數(shù)的msg_signature
* @param timeStamp 時(shí)間戳,對(duì)應(yīng)URL參數(shù)的timestamp
* @param nonce 隨機(jī)串,對(duì)應(yīng)URL參數(shù)的nonce
* @param echoStr 隨機(jī)串,對(duì)應(yīng)URL參數(shù)的echostr
*
* @return 解密之后的echostr
* @throws AesException 執(zhí)行失敗,請(qǐng)查看該異常的錯(cuò)誤碼和具體的錯(cuò)誤信息
*/
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;
}
}
/**
* 對(duì)公眾平臺(tái)發(fā)送給公眾賬號(hào)的消息加解密示例代碼.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
// ------------------------------------------------------------------------
package com.qq.weixin.mp.aes;
import java.security.MessageDigest;
import java.util.Arrays;
/**
* SHA1 class
*
* 計(jì)算公眾平臺(tái)的消息簽名接口.
*/
class SHA1 {
/**
* 用SHA1算法生成安全簽名
* @param token 票據(jù)
* @param timestamp 時(shí)間戳
* @param nonce 隨機(jī)字符串
* @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;
/**
* 刪除解密后明文的補(bǔ)位字符
*
* @param decrypted 解密后的明文
* @return 刪除補(bǔ)位字符后的明文
*/
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);
}
}
三、總結(jié)
企業(yè)通過(guò)參數(shù)msg_signature對(duì)請(qǐng)求進(jìn)行校驗(yàn),如果確認(rèn)此次GET請(qǐng)求來(lái)自企業(yè)號(hào),那么企業(yè)應(yīng)用對(duì)echostr參數(shù)解密并原樣返回echostr明文(不能加引號(hào)),則接入驗(yàn)證生效,回調(diào)模式才能開啟。開啟后一些功能會(huì)陸續(xù)實(shí)現(xiàn),敬請(qǐng)期待!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 圖文介紹報(bào)表與企業(yè)微信公眾號(hào)集成方案
- 微信開發(fā)--企業(yè)轉(zhuǎn)賬到用戶
- 微信企業(yè)號(hào) 根據(jù)錯(cuò)誤碼返回錯(cuò)誤信息類封裝
- 微信企業(yè)號(hào)驗(yàn)證/發(fā)送/接收消息
- java微信企業(yè)號(hào)開發(fā)之通訊錄
- java微信企業(yè)號(hào)開發(fā)之發(fā)送消息(文本、圖片、語(yǔ)音)
- 微信企業(yè)號(hào)開發(fā)之微信考勤Cookies的使用
- 微信企業(yè)號(hào)開發(fā)之微信考勤百度地圖定位
- 微信公眾號(hào)支付之坑:調(diào)用支付jsapi缺少參數(shù) timeStamp等錯(cuò)誤解決方法
- php版微信開發(fā)Token驗(yàn)證失敗或請(qǐng)求URL超時(shí)問(wèn)題的解決方法
- [企業(yè)公眾號(hào)]升級(jí)到[企業(yè)微信]之后發(fā)送消息失敗的解決方法
相關(guān)文章
SpringBoot 使用Mybatis分頁(yè)插件實(shí)現(xiàn)詳解
這篇文章主要介紹了SpringBoot 使用Mybatis分頁(yè)插件實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
spring?Bean創(chuàng)建的完整過(guò)程記錄
這篇文章主要給大家介紹了關(guān)于Spring中Bean實(shí)例創(chuàng)建的相關(guān)資料,文中通過(guò)實(shí)例代碼和圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01
mybatis 多表關(guān)聯(lián)mapper文件寫法操作
這篇文章主要介紹了mybatis 多表關(guān)聯(lián)mapper文件寫法操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
基于Java堆內(nèi)存的10個(gè)要點(diǎn)的總結(jié)分析
本篇文章是對(duì)Java堆內(nèi)存的10個(gè)要點(diǎn)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
SpringBoot整合新版SpringSecurity完整過(guò)程
Spring Security是保障Spring應(yīng)用程序安全的強(qiáng)大框架,而新版的Spring Security引入了lambda表達(dá)式來(lái)配置,使得安全配置更加簡(jiǎn)潔、優(yōu)雅,本文將介紹如何在Spring Boot項(xiàng)目中整合新版Spring Security,需要的朋友可以參考下2024-02-02

