🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
##请求校验流程 ###简介 我们要开发的请求校验程序必须能够处理HTTP GET 请求,而且要对请求者进行身份校验,以确保请求来自微信服务器,请求校验流程如下: 1. 获取HTTP GET请求中的4个参数:signatrue、timestamp、nonce和echostr; 2. 将token、timestamp和nonce 3个参数按**字典序**排序; 3. 将排序后的3个参数按顺序拼接成一个字符串,并对该字符串进行sha1 加密; 4. 将sha1 加密后的字符串与参数signature进行对比,如果相等则证明该请求来自微信服务器。 * * * * * ######**提示**:步骤2提到的参数token 不是从GET请求中获取的,而是由开发者指定的。在启用开发者模式时,也会要求填写token,这两处token要求保持一致 * * * * * ###请求校验流程分析 在Java中,处理HTTP GET请求就需要用到Servlet(也可以使用JSP或者Struts,但本质也是Servlet),在Servlet中 接收参数 signature、timestamp、nonce和echostr,代码如下所示 ~~~ String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String echostr = request.getParameter("echostr"); ~~~ 要对token、timestamp、和nonce 3个参数按照 字典序 排序,可以使用java.util.Arrays类的sort()方法;而将排序后的结果拼接成一个字符串,可以使用String类的contact()方法,实现代码如下: ~~~ //对token、timestamp和nonce排序 String[] paramArr = new String[] {token,timestamp,nonce}; Arrays.sort(paramArr); //将排序后的结果拼接成一个字符串 String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]); ~~~ 对拼接后的字符串content进行sha1加密可以使用java.security.MessageDigest类来实现,代码如下: ~~~ MessageDigest md = MessageDigest.getInstance("SHA-1"); //对拼接后的字符串进行sha1加密 byte[] digest = md.digest(content.getBytes()); ~~~ 可以看到,进行sha1加密后的结果是一个byte数组,而我们需要的是一个字符串。所以还需要通过下面的方法将byte数组转换为字符串: ~~~ /** * 将字节数组转换为十六进制字符串 * @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 ib * @return * / private static String byteToHexStr(byte ib) { char[] Digit = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; char[] ob = new char[2]; ob[0] = Digit[(ib >>> 4) & 0X0F]; ob[1] = Digit[ib & 0X0F]; String s = new String(ob); return s; } ~~~ 调用上面的 byteToStr()方法将sha1加密后的byte 数组转换成字符串,如下所示: ~~~ String ciphertext = byteToStr(digest); ~~~ 最后,还要讲字符串ciphertext 与参数signature进行比较,如果相等,则将参数echostr原样返回,代码如下 ~~~ PrintWriter out = response.getWriter(); //请求校验,若校验成功则原样返回echostr if(ciphertext.equals(signature.toUpperCase())){ out.print(echostr); } out.close(); ~~~ ###请求校验程序实现和封装 1. 首先,新建一个名为 test 的Web项目,在项目的src下创建一个普通Java类SignUtil,该类对请求校验流程的实现进行了封装,方便在Servlet中调用。代码如下: [SignUtil.java](http://www.kancloud.cn/yongxin/wxapi/195098) 2. 创建一个Servlet类,用于接收GET请求传递的4个参数,并调用SignUtil 工具类中封装的checkSignature()方法进行请求校验,如果校验成功,则将接收到的参数echostr原样返回。代码如下: [SignServlet.java](http://www.kancloud.cn/yongxin/wxapi/195105) 3. Servlet创建完成后还需要在web.xml中进行配置,配置如下 ~~~ <?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"> <servlet> <servlet-name>signServlet</servlet-name> <servlet-class> test.liu.sign.servlet.SignServlet </servlet-class> </servlet> <!-- /coreServlet用于指定该Servlet的访问路径 --> <servlet-mapping> <servlet-name>signServlet</servlet-name> <url-pattern>/signServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> ~~~ 在web.xml中需要特别注意的是 <url-pattern> 元素,它指定了SignServlet 的访问路径。例如,将项目部署到本机端口8080的tomcat下,根路径指的是 localhost:8080/test/,SignServlet的访问路径就是 localhost:8080/test/SignServlet