Java開發微信公眾號(二)——開發請求校驗程式
開發IDE:MyEclipse或Eclipse或IDEA都可以,我現在用的是MyEclipse。
請求校驗流程分析
上一篇中我們講了微信開發環境的搭建,下面就來寫請求校驗程式的開發,目的是是為了驗證訊息的確來自微信伺服器。
開發者提交資訊後,微信伺服器將傳送GET請求到填寫的伺服器地址URL上,GET請求攜帶引數如下表所示:
開發者通過檢驗signature對請求進行校驗,若確認此次GET請求來自微信伺服器,原樣返回echostr引數內容,則接入生效,否則接入失敗。加密/校驗流程如下:
- 將token、timestamp、nonce三個引數進行字典排序;
- 將三個引數字串拼接成一個字串進行sha1加密;
- 開發者獲得加密後的字串可與signature對比,標識該請求來源於微信。
注意:微信公眾號介面必須以
http://
或https://
開頭,分別支援80埠和443埠。
請求校驗程式的實現
SignUtil類封裝請求校驗流程
新建一個名為wechat_read的web專案,在專案的src下新建一個工具類SignUtil,該類對請求校驗流程的實現進行了封裝,方便在Servlet中呼叫。SignUtil類的程式碼如下【參考書籍《微信公眾平臺應用開發》——柳峰】:
package com.zrxjuly.read.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
* 描述:請求校驗工具類.
* @author zrxJuly
* @createDate 2017-12-9
* @since 1.0
*
*/
public class SignUtil {
// 與開發模式介面配置資訊中的Token保持一致.
private static String token = "weixinCourse";
/**
* 校驗簽名
* @param signature 微信加密簽名.
* @param timestamp 時間戳.
* @param nonce 隨機數.
* @return
*/
public static boolean checkSignature(String signature, String timestamp, String nonce) {
// 對token、timestamp、和nonce按字典排序.
String[] paramArr = new String[] {token, timestamp, nonce};
Arrays.sort(paramArr);
// 將排序後的結果拼接成一個字串.
String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
String ciphertext = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 對拼接後的字串進行sha1加密.
byte[] digest = md.digest(content.toString().getBytes());
ciphertext = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 將sha1加密後的字串與signature進行對比.
return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false;
}
/**
* 將位元組陣列轉換為十六進位制字串.
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 將位元組轉換為十六進位制字串.
* @param mByte
* @return
*/
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;
}
}
CoreServlet類接收GET請求傳遞的引數
建立一個Servlet類,用於接收Get請求傳遞的4個引數,並呼叫SignUtil工具類中封裝的checkSignature()方法進行請求校驗,如果校驗成功,則將接收到的引數echostr原樣返回。CoreServlet類:
package com.zrxjuly.read.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zrxjuly.read.util.MessageHandlerUtil;
import com.zrxjuly.read.util.SignUtil;
/**
* 請求處理的核心類.
* @author zrxJuly
* @createDate 2017-12-9
* @since TODO: 1.0
*
*/
public class CoreServlet extends HttpServlet {
/**
* 請求校驗(確認請求來自微信伺服器).
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("=======開始請求校驗======");
// 微信加密簽名.
String signature = request.getParameter("signature");
System.out.println("signature====" + signature);
// 時間戳.
String timestamp = request.getParameter("timestamp");
System.out.println("timestamp====" + timestamp);
// 隨機數.
String nonce = request.getParameter("nonce");
System.out.println("nonce====" + nonce);
// 隨機字串.
String echostr = request.getParameter("echostr");
System.out.println("echostr====" + echostr);
PrintWriter out = response.getWriter();
// 請求校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗.
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
System.out.println("=======請求校驗成功======" + echostr);
out.print(echostr);
}
out.close();
out = null;
}
/**
* 處理微信伺服器發來的訊息.
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 將請求、響應的編碼均設定為UTF-8(防止中文亂碼)
}
}
web.xml中配置servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<servlet>
<servlet-name>coreServlet</servlet-name>
<servlet-class>com.zrxjuly.read.servlet.CoreServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>coreServlet</servlet-name>
<url-pattern>/coreServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
部署執行專案
請求校驗程式寫完後,我們將專案部署到tomcat(tomcat埠號是8080)上,執行。用上一節的公網對映:首先找到我們之前下載的natapp.exe,因為上一篇中我們已經運行了,所以這一次直接雙擊開啟就可以了。在瀏覽器位址列中輸入forwarding
然後輸入專案啟動完整路徑:http://你的forwarding/wechat_read/coreServlet
,發現專案報空指標異常,如下圖:
這是因為沒有傳那四個引數,我們下一步需要配置介面配置資訊。
介面配置資訊中填入對映的外網地址和token
登入進入微信公眾平臺介面測試管理頁面https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login,配置介面配置資訊:
特別注意:一定要先將本地專案部署執行之後再配置該介面資訊,才能配置成功,否則就會配置失敗。
這樣我們的請求校驗程式就完成了。簡單來理解,請求校驗的目的就是為了證明請求是微信伺服器發出的,為了驗證訊息是來自微信伺服器。
如果在操作過程中有問題,歡迎隨時討論^.^