前言:

在我写这篇文章之前,博主就已经看了一下微信公众号以及微信小程序的历史,不得不感叹自己老了!随着最近几年Native App的兴起和衰落,自己本认为可以火的Native App现在逐渐被一些light App所挤占,很大一部分尤以腾讯的微信为平台!

这篇文章主要是记录自己开始微信开发的第一页,也是目前比较紧急的事情,因为要为公司开发一款微信公众号,虽然开发已经过去2个月了,2个月自己也是跌跌撞撞,做了很多自己不擅长的事情,产品需求的分析与设计,界面的设计与编写,产品的架构…..很多自己不敢想象的事情还是做了!

准备工作

  1. 拥有一款已经注册且通过的认证号或者服务号
  2. 拥有一个独立服务器(自己用的花生壳,可以免费内网映射1G流量)
  3. ….貌似没有了(其实读者应该去看一下开发文档文档)

接入微信公众号

接入微信公众号也就是通俗上的告诉微信服务器,你的服务器就是你自己申请的微信公众号的服务器。(验证服务器是否被微信识别)

如何接入微信公众号

登录微信公众平台->开发->开发者工具->公众平台测试帐号->接口配置信息->修改

  1. 配置url
  2. 配置token

流程:

  1. 配置URL和token之后,微信公众号会向配置好的url发送一个get请求,将会携带如下4个参数(token就是我们刚刚配置的)
    signature微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
    timestamp时间戳
    nonce随机数
    echostr随机字符串
  2. 将token、timestamp、nonce三个参数进行字典序排序(升序)
  3. 将三个参数字符串拼接成一个字符串进行sha1加密(得到的是一个加密后的十六进制字符串)
  4. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
  5. 如果请求通过,我们需要返回一个echostr(微信服务器传给我们的)给微信服务器

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
* @date 2017年11月23日 下午2:44:22
* @author SiVan
*/
package com.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

/**
* @param signature 微信加密签名,
* @param timestamp 时间戳
* @param nonce 随机数
* @author SiVan
* @time 2017年11月23日 下午2:44:22
* @TODO TODO 请求校验程序的实现
*/
public class CheckUtil {

/*微信测试号接口配置信息的Token,内容要完全一致*/
private static final String token = "123456";

/**
* 将token,timestamp,nonce 三个参数的内容进行字典序排序,
* 拼接成字符串,并且进行SHA-1加密,与signature进行比对,如果一致返回true,否则返回false
* @param signature 微信加密签名,
* @param timestamp 时间戳
* @param nonce 随机数
* @return
*/
public static boolean check(String signature, String timestamp, String nonce) {

/*进行字典序排序*/
String[] params = new String[] { token, timestamp, nonce };
Arrays.sort(params);

/*排序后的字符串进行拼接*/
StringBuffer sb = new StringBuffer();
sb = sb.append(params[0]).append(params[1]).append(params[2]);


/*进行加密*/
String cipherText = sb.toString();
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] digest = md.digest(cipherText.getBytes());
cipherText = byteToString(digest);

return cipherText != null ? cipherText.equals(signature.toUpperCase()) : false;

}

/*字节数组转换为十六进制字符串*/
private static String byteToString(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}

return strDigest;
}

/*字节转换为十六进制字符串*/
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;
}

}

测试程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/**
* @date 2017年11月22日 下午8:05:42
* @author SiVan
*/
package com.servlet;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

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

import com.util.CheckUtil;

/**
* @author SiVan
* @time 2017年11月22日 下午8:05:42
* @TODO TODO 验证消息来自微信服务器
*
* 请求
*
*/
public class SignUtil extends HttpServlet{
/**
* 1)将token、timestamp、nonce三个参数进行字典序排序

2)将三个参数字符串拼接成一个字符串进行sha1加密,加密后的字符串是十六进制的

3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

checkSign( request, response);

}

/**
* @param request
* @param response
* @throws IOException
*/
private void checkSign(HttpServletRequest request, HttpServletResponse response) throws IOException {
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");


/*验证通过回写echostr*/
if( CheckUtil.check(signature, timestamp, nonce))
{
response.getWriter().print(echostr);
}else{
response.getWriter().print("false");
}
}
}

注意:url配置的时候需要具体到我们接收参数的地址

请求校验的原因:

为了防止他人向公众号服务器发送恶意请求,需要对每个消息请求进行合法校验,微信服务器向公众号服务器POST消息时,也会在URL后面追加4个参数,分别是signature,timestamp,nonce,echostr,依然是通过校验签名判断消息的真实性!与上面讲的完全一致!


总结:当你点击在配置URL和Token点击提交的时候,如果配置失败,那么请你重新检查一下你的程序,确保你返回了echostr,如果配置成功,那么恭喜你,你的服务器算得上一个微信公众号服务器了2333!