1. 程式人生 > >java微信公眾平臺開發二(請求來源校驗)

java微信公眾平臺開發二(請求來源校驗)

上次我們進行tkozen 認真的時候卻沒有校驗請求的來源是否來自微信伺服器,這次我們加上這個校驗。

首先官方這樣描述首先我們要編寫個sha1加密的演算法,網上很多例子

SHA1:

public class SHA1 {  

   private static final boolean hexcase = false;  
   private static final int chrsz = 8;  

   // 得到字串SHA-1值的方法  
   public static String hex_sha1(String s) {  
       s = (s == null) ? "" : s;  
       return binb2hex(core_sha1(str2binb(s), s.length() * chrsz));  
   }  

   private static String binb2hex(int[] binarray) {  
       String hex_tab = hexcase ? "0123456789abcdef" : "0123456789abcdef";  
       String str = "";  

       for (int i = 0; i < binarray.length * 4; i++) {  
           char a = (char) hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xf);  
           char b = (char) hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 0xf);  
           str += (new Character(a).toString() + new Character(b).toString());  
       }  
       return str;  
   }  

   private static String binb2str(int[] bin) {  
       String str = "";  
       int mask = (1 << chrsz) - 1;  

       for (int i = 0; i < bin.length * 32; i += chrsz) {  
           str += (char) ((bin[i >> 5] >>> (24 - i % 32)) & mask);  
       }  
       return str;  
   }  

   private static int[] core_sha1(int[] x, int len) {  
       int size = (len >> 5);  
       x = strechbinarray(x, size);  
       x[len >> 5] |= 0x80 << (24 - len % 32);  
       size = ((len + 64 >> 9) << 4) + 15;  
       x = strechbinarray(x, size);  
       x[((len + 64 >> 9) << 4) + 15] = len;  

       int[] w = new int[80];  
       int a = 1732584193;  
       int b = -271733879;  
       int c = -1732584194;  
       int d = 271733878;  
       int e = -1009589776;  

       for (int i = 0; i < x.length; i += 16) {  
           int olda = a;  
           int oldb = b;  
           int oldc = c;  
           int oldd = d;  
           int olde = e;  

           for (int j = 0; j < 80; j++) {  
               if (j < 16) {  
                   w[j] = x[i + j];  
               } else {  
                   w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);  
               }  

               int t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));  

               e = d;  
               d = c;  
               c = rol(b, 30);  
               b = a;  
               a = t;  
           }  

           a = safe_add(a, olda);  
           b = safe_add(b, oldb);  
           c = safe_add(c, oldc);  
           d = safe_add(d, oldd);  
           e = safe_add(e, olde);  
       }  

       int[] retval = new int[5];  

       retval[0] = a;  
       retval[1] = b;  
       retval[2] = c;  
       retval[3] = d;  
       retval[4] = e;  

       return retval;  
   }  

   private static int rol(int num, int cnt) {  
       return (num << cnt) | (num >>> (32 - cnt));  
   }  

   private static int safe_add(int x, int y) {  
       int lsw = (int) (x & 0xffff) + (int) (y & 0xffff);  
       int msw = (x >> 16) + (y >> 16) + (lsw >> 16);  

       return (msw << 16) | (lsw & 0xffff);  
   }  

   private static int sha1_ft(int t, int b, int c, int d) {  
       if (t < 20)  
           return (b & c) | ((~b) & d);  

       if (t < 40)  
           return b ^ c ^ d;  

       if (t < 60)  
           return (b & c) | (b & d) | (c & d);  

       return b ^ c ^ d;  
   }  

   private static int sha1_kt(int t) {  
       return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514;  
   }  

   public static String str_sha1(String s) {  
       s = (s == null) ? "" : s;  

       return binb2str(core_sha1(str2binb(s), s.length() * chrsz));  
   }  

   private static int[] str2binb(String str) {  
       str = (str == null) ? "" : str;  

       int[] tmp = new int[str.length() * chrsz];  
       int mask = (1 << chrsz) - 1;  

       for (int i = 0; i < str.length() * chrsz; i += chrsz) {  
           tmp[i >> 5] |= ((int) (str.charAt(i / chrsz)) & mask) << (24 - i % 32);  
       }  

       int len = 0;  
       for (int i = 0; i < tmp.length && tmp[i] != 0; i++, len++)  
           ;  

       int[] bin = new int[len];  

       for (int i = 0; i < len; i++) {  
           bin[i] = tmp[i];  
       }  

       return bin;  
   }  

   private static int[] strechbinarray(int[] oldbin, int size) {  
       int currlen = oldbin.length;  

       if (currlen >= size + 1) {  
           return oldbin;  
       }  

       int[] newbin = new int[size + 1];  
       for (int i = 0; i < size; newbin[i] = 0, i++)  
           ;  

       for (int i = 0; i < currlen; i++) {  
           newbin[i] = oldbin[i];  
       }  

       return newbin;  
   }  
} 

2.編寫個輔助類用於請求來源校驗

import java.util.Arrays;

public class Util {
	public static final String tokzen="tailre";
	
	/**
	 * 對請求進行校驗,看是否來自微信伺服器
	 * @param signature
	 * @param timestamp
	 * @param nonce
	 * @return
	 */
	public static boolean isSignature(String signature,String timestamp,String nonce){
		boolean flag=false;
		String [] array={tokzen,timestamp,nonce};
		
		//字典排序
		Arrays.sort(array);
		StringBuilder str= new StringBuilder();
		for(String temp:array){
			str.append(temp);
		}
		
		//加密
		String signature2=SHA1.hex_sha1(str.toString());
		
		//判斷和伺服器傳來的是否相同
		if(signature.equals(signature2))
			flag=true;
		
		return flag;
	}
}
3.修改上次的demoServlet 如下:
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class Servlet extends HttpServlet {
	
	
	@Override
	public void destroy() {
		super.destroy();
	}
	
	@Override
	public void init() throws ServletException {
		super.init();
	}
	
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String signature = request.getParameter("signature");//微信加密簽名
      String timestamp = request.getParameter("timestamp");//時間戳
      String nonce = request.getParameter("nonce");//隨機數
      String echostr = request.getParameter("echostr");//隨機字串

      //對接收到的引數做資料驗證,來確認該請求來自微信,避免被第三方隨意攻擊
      if(Util.isSignature(signature, timestamp, nonce))
      	//驗證通過後,需要將隨機字串原樣返回給微信,微信才確認你的這個服務正常
      	response.getWriter().print(echostr);

     

	}
	
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}
}
4.重新測試下tokzen 是否通過就OK了!