- A+
所属分类:微信公众号
首先上图
提交时不停提示token验证失败。但是从描述来看,必须为英文或数字,长度为3-32字符。这尼玛我难道不是英数字?填别的什么你也没告诉我啊!
没办法,这个说明真的太烂了,只能各种百度谷歌。但是看了很多基本上都没说清楚。根据几篇文章理解后,自己试了下,终于成功了。这里必须得问候下微信写文档的人。写清楚点会死啊。
微信需要一个请求一个URL来响应token验证,so !!! 也就是你点击确定的时候是向你指定的URL发送一个请求,在请求里面验证你的token是否正确。也就是我们需要一个外网接口让微信访问,这个接口不需要传入任何参数;注意必须是外网服务器接口,微信才能调用.
所以需要一个接口放在服务器上,接口代码如下
@Controller public class WechatController { private static Logger logger = Logger.getLogger(WechatController.class); private static String token = "jinsanpang"; @RequestMapping("/weixin") public void get(HttpServletRequest request, HttpServletResponse response) throws Exception { logger.error("WechatController ---- WechatController"); System.out.println("========WechatController========= "); logger.info("请求进来了..."); Enumeration pNames = request.getParameterNames(); while (pNames.hasMoreElements()) { String name = (String) pNames.nextElement(); String value = request.getParameter(name); // out.print(name + "=" + value); String log = "name =" + name + " value =" + value; logger.error(log); } PrintWriter out = response.getWriter(); out.print(token); out.close(); out = null; } }
这里必须注意微信配置里的Url必须与后台函数上的url相匹配,不然进不了后台的方法。
我们发现微信传来四个键值对,分别是:
signature :微信加密签名
echostr:随机字符串
timestamp:时间戳
noce:随机数
可以看到这里并没有token,什么鬼?别慌,继续百度,直接上代码
private static String token = "1234567890"; /** * 校验签名 */ public static boolean checkSignature(String signature, String timestamp, String nonce) { System.out.println("signature:" + signature + "timestamp:" + timestamp + "nonc:" + nonce); String[] arr = new String[] { token, timestamp, nonce }; // 将token、timestamp、nonce三个参数进行字典序排序 Arrays.sort(arr); StringBuilder content = new StringBuilder(); for (int i = 0; i < arr.length; i++) { content.append(arr[i]); } MessageDigest md = null; String tmpStr = null; try { md = MessageDigest.getInstance("SHA-1"); // 将三个参数字符串拼接成一个字符串进行sha1加密 byte[] digest = md.digest(content.toString().getBytes()); tmpStr = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } content = null; // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信 System.out.println(tmpStr.equals(signature.toUpperCase())); return tmpStr != null ? tmpStr.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; }
这是一个加密过程 , 蛋疼的过程,那么回到正题;如何让token验证通过了?
我们看下最终的代码
@Controller public class WechatController { private static Logger logger = Logger.getLogger(WechatController.class); private static String WECHAT_TOKEN = "jinsanpang"; @RequestMapping(value = "/weixin") public void get(HttpServletRequest request, HttpServletResponse response) throws Exception { logger.error("WechatController ---- WechatController"); System.out.println("========WechatController========= "); logger.info("请求进来了..."); Enumeration pNames = request.getParameterNames(); while (pNames.hasMoreElements()) { String name = (String) pNames.nextElement(); String value = request.getParameter(name); // out.print(name + "=" + value); String log = "name =" + name + " value =" + value; logger.error(log); } String signature = request.getParameter("signature");/// 微信加密签名 String timestamp = request.getParameter("timestamp");/// 时间戳 String nonce = request.getParameter("nonce"); /// 随机数 String echostr = request.getParameter("echostr"); // 随机字符串 PrintWriter out = response.getWriter(); if (SignUtil.checkSignature(signature, timestamp, nonce)) { out.print(echostr); } out.close(); out = null; } }
总结下,这个微信验证的原理:微信使用我们提供的token,通过算法生成签名,然后将这几个参数传给我们,我们服务端通过我们提供的token按照微信的算法得出一个值,如果是同一个值说明token有效。
很蛋疼。。这两天在搞微信项目发现一个特点,那就是虽然有官方文档,但是很多地方写的很粗,有些东西必须百度才能解决,作为一个官方文档这样真的蛋疼。。