1. 程式人生 > >Java開發微信公眾號(二)——開發請求校驗程式

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,配置介面配置資訊:

特別注意:一定要先將本地專案部署執行之後再配置該介面資訊,才能配置成功,否則就會配置失敗。

這樣我們的請求校驗程式就完成了。簡單來理解,請求校驗的目的就是為了證明請求是微信伺服器發出的,為了驗證訊息是來自微信伺服器。
如果在操作過程中有問題,歡迎隨時討論^.^