一 验证消息的确来自微信服务器
1. 开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:
参数 | 描述 |
---|---|
signature | 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |
timestamp | 时间戳 |
nonce | 随机数 |
echostr | 随机字符串 |
开发者通过检验signature对请求进行校验,加密/校验流程如下:
1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与signature对比,
4) 若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。
二 代码
2.1 编写sha1方法,完整java代码如下:
/** * 验签 * @param token 自定义的token * @param timestamp 时间戳 * @param nonce 随机数 * @param signature 微信加密签名 * @return */ public static boolean getSha(String token,String timestamp,String nonce,String signature) { try { // (1)将token、timestamp、nonce三个参数进行字典序排序 String[] array = new String[] { token, timestamp, nonce}; StringBuffer sb = new StringBuffer(); // 字符串排序 Arrays.sort(array); for (int i = 0; i < 3; i++) { sb.append(array[i]); } String str = sb.toString(); //(2)将三个参数字符串拼接成一个字符串进行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); } log.info("微信加密签名signature====>"+signature); log.info("用SHA算法生成安全签名后的数据:=====>>"+hexstr.toString()); if(signature.equals(hexstr.toString())) { log.info("接入成功"); return true; }else{ log.info("微信加密签名与SHA算法生成安全签名比对失败!"); return false; } } catch (NoSuchAlgorithmException e) { log.info("微信加密签名与SHA算法生成安全签名比对过程中异常!"); return false; } }
2.2 完整接口代码如下
package com.grand.weichat.controller; import java.io.IOException; import java.io.PrintWriter; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.grand.weichat.util.utils; import lombok.extern.log4j.Log4j; @Controller @Log4j public class WxServlet { @Value("${conf.token}") private String token; @RequestMapping("/wx") public void wxHandle(HttpServletRequest request, HttpServletResponse response) { try { /* signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 timestamp 时间戳 nonce 随机数 echostr 随机字符串*/ String signature=request.getParameter("signature"); String timestamp=request.getParameter("timestamp"); String nonce=request.getParameter("nonce"); String echostr=request.getParameter("echostr"); /** * 1)将token、timestamp、nonce三个参数进行字典序排序 * 2)将三个参数字符串拼接成一个字符串进行sha1加密 * 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 * 4)若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。 */ boolean result=utils.getSha(token,timestamp, nonce,signature); if(result) { log.info("接入成功"); PrintWriter out = response.getWriter(); out.print(echostr); out.flush(); out.close(); return; }else{ log.info("接入失败"); return; } } catch (IOException e) { log.info("接入失败"); return; } } }