总想自己动动手系列·3·如何让微信公众号和外网服务交互之通过TOKEN验证(准备篇·1)

Posted 小风微灵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了总想自己动动手系列·3·如何让微信公众号和外网服务交互之通过TOKEN验证(准备篇·1)相关的知识,希望对你有一定的参考价值。

一、准备工作

(1)准备一个微信公众号(对私的订阅号或者对公的服务号)。

(2)准备一台部署了web应用,并且已经发布出去的Linux服务器(需要说明的是:微信公众号强烈建议使用80端口,使用其他自定义端口貌似根本不通,后面会有说明)。

先科普说明一下:

  1.微信公众号的注册分为2种类型:对个人的订阅号,对企业的服务号,这个很简单,按照官方注册流程按部就班地填写基本不会出现问题。

 

  服务号:主要偏向于服务交互(功能类似12315,114,银行,提供绑定信息,服务交互),每月可群发4条消息;服务号适用人群:**媒体、企业、政府或其他组织。

 

  订阅号:主要偏向于为用户传达资讯,(功能类似报纸杂志,为用户提供新闻信息或娱乐趣事),每天可群发1条消息;订阅号适用人群**:个人、媒体、企业、政府或其他组织。

 

 

  2.刚注册的订阅号和公众号是“非认证”状态的(本人注册的是对私的订阅号,目前处于非认证状态)非认证的订阅号对接口的访问权限是很小的,连起码的自定义订阅号的菜单都不给,真气人!

       3.微信官方将认证审核流程托管到了第三方机构或公司,这个是要收取服务费的,对公的服务号收费标准:300¥/次/年。具体详细,网上是这样回答的:

 

我等会就去试一下如何认证,如果认证成功了,会出一篇具体介绍如何认证对私的订阅号的。本文注重介绍如何验证TOKEN的。

    4.用户操作访问微信公众号,请求是如何处理转发的呢?看完下面的示意图就会明白为什么要准备一台自己的服务器了。

 二、TOKEN验证的流程:

先假设,我们部署在服务器上的web应用已经可以正常被外网访问了。

(1)在微信公众号后台:开发-》基本设置菜单中

 

你以为就这么简单填写就把微信服务平台和自己的服务器web应用关联起来了???那是不可能滴!!!这样直接提交会报错

先简单介绍下图中的几个输入项和选择项到底是干嘛的!

1、URL:这个是TOKEN的验证调取的请求url,端口要求是80或者443,我们一般用80端口。

2、Token:这个是微信服务和自己的服务之间通信的关键通信凭证(也可以这么理解:开发者自定的验证口令)。

3、EncodingAESKey:你也可以理解为通信信息加密因子,这个让他它自动生成即可。

4、消息加解密方式:明文模式:不加解密(新手开发者建议选这个,方便开发和调试)。

(2)在自己服务器web项目中需要做调整,调整流程如下:

1、新建一个servlet.java用于处理微信服务器发送过来的Token验证请求: 

package com.xfwl.weixinToken;

import java.io.IOException;
import java.io.PrintWriter;

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

public class WXServletToken extends HttpServlet {

    /**
     * 构造器
     */
    public WXServletToken() {
        super();
    }

    /**
     * 销毁操作
     */
    public void destroy() {
        super.destroy();
    }

    /**
     * doGet请求处理
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /**
         * 获取weixin请求参数
         */
        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(CheckUtil.checkSignature(signature, timestamp, nonce)){
            //如果校验成功,将得到的随机字符串原路返回
            out.print(echostr);
        }
        out.flush();
        out.close();
    }

    /**
     * doPost请求操作
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC \\"-//W3C//DTD HTML 4.01 Transitional//EN\\">");
        
        out.flush();
        out.close();
    }

    /**
     *初始化操作
     */
    public void init() throws ServletException {}

}

 2、新建一个TOKEN验证类 

 1 package com.xfwl.weixinToken;
 2 
 3 import java.security.MessageDigest;
 4 import java.security.NoSuchAlgorithmException;
 5 import java.util.Arrays;
 6 
 7 /**
 8  * 微信Token校验
 9  * @author Jason
10  *
11  */
12 public class CheckUtil {
13     /**
14      * 加密规则
15      */
16     public static final String wx_mdType="SHA1";
17     /**
18      * 微信公众号Token信息
19      */
20     public static final String wx_token="*****";
21     /**
22      * 校验微信Token的有效性
23      * @param signature 
24      * @param timestamp 时间戳
25      * @param nonce
26      * @return
27      */
28     public static boolean checkSignature(String signature,String timestamp,String nonce){
29         //1、定义数组存放wx_token、timestamp、nonce
30         String[] arr={wx_token,timestamp,nonce};
31         //2、对数组进行排序
32         Arrays.sort(arr);
33         //3、生成字符串
34         StringBuffer sb=new StringBuffer();
35         for(String s:arr){
36             sb.append(s);
37         }
38         String temp=getSha1(sb.toString());
39         if(temp==null){
40             return false;
41         }
42         return temp.equals(signature);
43     }
44     public static String getSha1(String data){
45         if(data==null || data.length()==0){
46             return null;
47         }
48         char[] hexDigist={\'0\',\'1\',\'2\',\'3\',\'4\',\'5\',\'6\',\'7\',\'8\',\'9\',\'a\',\'b\',\'c\',\'d\',\'e\',\'f\'};
49         try {
50             MessageDigest mdTemp=MessageDigest.getInstance(wx_mdType);
51             mdTemp.update(data.getBytes());
52             byte[] md=mdTemp.digest();
53             int j=md.length;
54             char[] buf=new char[j*2];
55             int k=0;
56             for(int i=0;i<j;i++){
57                 byte byte0=md[i];
58                 buf[k++]=hexDigist[byte0 >>> 4 & 0xf];
59                 buf[k++]=hexDigist[byte0 & 0xf];
60             }
61             return new String(buf);        
62             
63         } catch (NoSuchAlgorithmException e) {
64             System.out.println("微信公众号TOKEN加密失败");
65             return null;
66         }
67     }
68 }

  3、web.xml中配置请求(当然了,用注解形式也可,方式很多种,任选随意)

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app version="3.0" 
 3     xmlns="http://java.sun.com/xml/ns/javaee" 
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 5     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 6     http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
 7   <display-name></display-name>    
 8   <!-- 默认界面 -->
 9       <welcome-file-list>
10         <welcome-file>index.jsp</welcome-file>
11       </welcome-file-list>
12   <!-- 配置过滤器 -->
13     <!-- <filter>  
14       <filter-name>filter</filter-name>  
15       <filter-class>com.xfwl.filter.RequestFilter</filter-class>  
16       <init-param>  
17           <param-name>charset</param-name>  
18           <param-value>UTF-8</param-value>  
19       </init-param>  
20       <init-param>  
21           <param-name>contentType</param-name>  
22           <param-value>text/html;charset=UTF-8</param-value>  
23       </init-param>  
24      </filter>  
25      <filter-mapping>  
26           <filter-name>filter</filter-name>  
27           * 代表截获所有的请求  或指定请求/test.do  /xxx.do  
28           <url-pattern>/*</url-pattern>  
29       </filter-mapping> -->
30       <!-- 接入微信Token验证 -->
31       <servlet>
32         <servlet-name>WXServletToken</servlet-name>
33         <servlet-class>com.xfwl.weixinToken.WXServletToken</servlet-class>
34       </servlet>
35     
36       <servlet-mapping>
37         <servlet-name>WXServletToken</servlet-name>
38         <url-pattern>/servlet/WXServletToken</url-pattern>
39       </servlet-mapping>
40 </web-app>

 4、打war包,重新部署启动

5、回到微信公众号后台:开发-》基本设置菜单中,输入对应的信息,点击提交按钮。即可提交设置成功。

需要说明一点:图中“IP白名单设置”,这个需要把自己服务器外网IP加上,如果你还需要使用微信公众号的接口调试功能去测试接口的话,那么微信公众号平台的IP(39.130.165.18)也需要加入白名单中。

6、到这一步:就已经完成了TOKEN的验证了。

 

以上是关于总想自己动动手系列·3·如何让微信公众号和外网服务交互之通过TOKEN验证(准备篇·1)的主要内容,如果未能解决你的问题,请参考以下文章

python系列教程183——global语句

python系列教程183——global语句

计算1-1/3+1/5-1/7+···的前n项和

书列君荐书|《黑天鹅·如何应对不可预知的未来》美纳西姆·尼古拉斯·塔勒布 著

新手···毒舌揭短

致自己·