在上一篇文章中,樓主介紹了在微信公衆號開發過程中的接入概述,同時實現了接入概述中的第一步,服務器相關配置,同時做了穿透測試,實現了外網用戶訪問本地應用服務的可行性。
本篇文章將介紹接入概述中的第二步,驗證消息的確來自微信服務器。
在開發文檔中,對第二步的驗證,微信官方文檔給出了這樣的描述,樓主這裏直接把它貼過來。
開發者提交信息後,微信服務器將發送GET請求到填寫的服務器地址URL上,GET請求攜帶參數如下表所示:
參數 | 描述 |
---|---|
signature | 微信加密簽名,signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。 |
timestamp | 時間戳 |
nonce | 隨機數 |
echostr | 隨機字符串 |
開發者通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信服務器,請原樣返回echostr參數內容,則接入生效,成爲開發者成功,否則接入失敗。加密/校驗流程如下:
1)將token、timestamp、nonce三個參數進行字典序排序
2)將三個參數字符串拼接成一個字符串進行sha1加密
3)開發者獲得加密後的字符串可與signature對比,標識該請求來源於微信
具體實現代碼如下所示:
package service;
import java.security.MessageDigest;
import java.util.Arrays;
public class WxService {
private static final String TOKEN = "wxtest1";
/**
* 簽名驗證
* @param signature
* @param timestamp
* @param nonce
* @return
*/
public static boolean check(String signature, String timestamp, String nonce) {
/**
* 簽名驗證規則
* 1)將token、timestamp、nonce三個參數進行字典序排序
* 2)將三個參數字符串拼接成一個字符串進行sha1加密
* 3)開發者獲得加密後的字符串可與signature對比,標識該請求來源於微信
*/
//將token、timestamp、nonce三個參數進行字典序排序
String[] str = new String[]{TOKEN, timestamp, nonce};
Arrays.sort(str);
//將三個參數字符串拼接成一個字符串進行sha1加密
String str1 = str[0] + str[1] + str[2];
String encodeSignature = sha1(str1);
//開發者獲得加密後的字符串可與signature對比,標識該請求來源於微信
return encodeSignature.equalsIgnoreCase(signature);
}
/**
* sha1加密
*/
public static String sha1(String str) {
try {
//獲取一個加密對象
MessageDigest md = MessageDigest.getInstance("sha1");
//將獲取到的對象加密
byte[] digest = md.digest(str.getBytes());
char[] chars = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
StringBuilder builder = new StringBuilder();
//處理加密結果
for(byte b:digest) {
//高4位與15相與
builder.append(chars[(b>>4)&15]);
//低4位直接相與
builder.append(chars[b&15]);
}
return builder.toString();
}catch(Exception e) {
System.out.println("異常類型爲:" + e);
}
return null;
}
}
在處理邏輯過程中添加校驗方法的調用,具體代碼如下所示:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import service.WxService;
/**
* Servlet implementation class WxServlet
*/
@WebServlet("/wx")
public class WxServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public WxServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
*
* 參數 描述
* signature 微信加密簽名,signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。
* timestamp 時間戳
* nonce 隨機數
* echostr 隨機字符串
*
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// response.getWriter().append("Served at: ").append(request.getContextPath());
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
System.out.println("signature:" + signature);
System.out.println("timestamp:" + timestamp);
System.out.println("nonce:" + nonce);
System.out.println("echostr:" + echostr);
//驗證簽名
if(WxService.check(signature, timestamp, nonce)) {
// System.out.println("校驗成功");
PrintWriter writer = response.getWriter();
writer.print(echostr);
writer.flush();
writer.close();
}else {
System.out.println("校驗失敗");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// doGet(request, response);
System.out.println("post");
}
}
調用完成之後開始啓動測試,測試結果如下所示:
控制檯返回的結果如下所示:
至此,在接入概述中,前兩步已經完成,後續就是依賴接口文檔實現業務邏輯,這將會在後續的博客中陸續推出。