一、微信公众号第三方平台接口的时候,需要验证服务器有效性。
开发文档原文如下:
开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,参数有四个token、timestamp、nonce、signature
(四个参数的含义详见微信开发文档--接入:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319)
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。
加密/校验流程如下:1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
二、验证的工具类如下:
package com.weixin.Utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
* @author xx
* 类名:SignatureUtil
* 作用:开发者提交信息,验证服务器有效性
*/
public class SignatureUtil {
//与接口配置信息中的Token要一致
private static String token = "asd";
/**
* 用途:工具类,验证signature,如果验证成功,成为开发者,返回的是验证是否成功的布尔值
*/
public static boolean checkSignature(String signature, String timestamp, String nonce) {
//1 参数有四个token、timestamp、nonce、signature
//1.1 定义一个字符串类型的数组,将token、timestamp、nonce作为参数传进去
String[] arr = new String[] { token, timestamp, nonce };
//1.2 将token、timestamp、nonce三个参数进行字典序排序
Arrays.sort(arr);
//1.3 定义一个StringBuilder,遍历数组,将他们拼接起来,content
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
//2.将三个参数字符串拼接成一个字符串进行sha1加密
MessageDigest md =null;
String digeststr=null;
try {
//2.1 MessageDigest是java的加密类,为应用程序提供信息摘要算法的功能
md= MessageDigest.getInstance("SHA-1");
//2.2 MessageDigest的digest方法返回一个byte数组,我们选择的是入参是byte[]
byte[] digest = md.digest(content.toString().getBytes());
//2.3将byte数组的digest用byteToStr方法转换成字符串
digeststr=byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
//2.4将content置空
content =null;
//3.将sha1加密后的字符串可与signature对比,标识该请求来源于微信
return digeststr != null ? digeststr.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;
}
/**
* 将字节转换为十六进制字符串
* @入参 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;
}
}
三、验证的控制层如下:
/**
* @author xx
* 作用验证服务器地址有效性的controller
*/
@Controller
@RequestMapping("/wechat")
public class SignatureController {
private static Logger logger = Logger.getLogger(SignatureController.class);
//get请求,走的是地址栏传输,从地址栏上获取
@RequestMapping(value="/sign",method=RequestMethod.GET)
public void CheckSignature(HttpServletRequest request,HttpServletResponse response,
@RequestParam(value = "signature", required = true) String signature,
@RequestParam(value = "timestamp", required = true) String timestamp,
@RequestParam(value = "nonce", required = true) String nonce,
@RequestParam(value = "echostr", required = true) String echostr){
//1.获取后,调用我们的验证工具类,传入参数timestamp、nonce、signature,返回一个布尔值
boolean util=SignatureUtil.checkSignature(signature, timestamp, nonce);
//2.util返回ture,接入成功,返回false,接入失败
try {
if (util) {
/*System.out.println("接入成功");*/
//3.将echostr回写
PrintWriter out = response.getWriter();
out.print(echostr);
out.close();
} else {
/*System.out.println("接入失败");*/
logger.info("这里存在非法请求!");
}
} catch (Exception e) {
logger.error(e, e);
}
}
四、微信公众号配置服务器
开发>>基本配值>>服务器配置
有四项需要我们去配置:
1、服务器地址(URL),配置上访问地址,验证服务器有效性的时候使用。(http://服务器ip或者域名/工程名/wechat/sign)
2、令牌(Token),要与验证的工具类中的token一致。
3、消息加密密钥,可随机生成。
4、消息加密方式,明文模式。
五、配置完成后,点击提交就可以了