微信公众号基本配置里服务器配置时token验证失败Java解决办法

  • A+
所属分类:微信公众号

首先上图

微信公众号基本配置里服务器配置时token验证失败Java解决办法

提交时不停提示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有效。

很蛋疼。。这两天在搞微信项目发现一个特点,那就是虽然有官方文档,但是很多地方写的很粗,有些东西必须百度才能解决,作为一个官方文档这样真的蛋疼。。

ZPY

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: