- 背景需求:在开发微信小程序时,会存在用户需要向微信小程序发送消息或事件的需求,开发者希望小程序能响应用户的消息和需求或者在用户退出小程序后仍能推送相应的服务通知,都需要先进行后台服务器和微信服务器的之间的连接和验证。
- 目的:微信服务器会验证小程序开发者是否拥有正确的和它所请求的服务器地址相同的Token令牌
- 基于SpringBoot的JAVA代码():
1.controller层
@RestController
@RequestMapping("/wechat")
public class WechatController {
@Resource
private WechatService wechatService;
@GetMapping("/signature/check")
//微信服务器根据小程序配置的token,结合时间戳timestamp和随机数nonce通过SHA1生成签名,发起get请求,检验token的正确性,
//检验正确原样返回随机字符串echostr,失败返回空字符串
public String check(@RequestParam("signature")String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce")String nonce,
@RequestParam("echostr")String echostr){
return wechatService.checkSignature(signature,timestamp,nonce,echostr);
}
}
2.service层
public interface WechatService {
/**
*
* @param signature
* @param timestamp
* @param nonce
* @param echostr
* @return
*/
String checkSignature(String signature,String timestamp,String nonce,String echostr);
}
@Service
public class WechatServiceImpl implements WechatService {
@Override
public String checkSignature(String signature, String timestamp, String nonce, String echostr) {
try {
//这里的“token”是正确的token,由服务器定义,小程序只有使用正确的token,微信服务器才会验证通过
String checkSignature =SHA1.creatSHA1("token",timestamp,nonce);
if (checkSignature.equals(signature)){
return echostr;
}
} catch (AesException e) {
e.printStackTrace();
}
return null;
}
}
3.Util类
//SHA1加密算法类
public class SHA1 {
/**
*
* @param token
* @param timestamp 时间戳
* @param nonce 随机字符串
* @return 安全签名
* @throws AesException
*/
public static String creatSHA1(String token, String timestamp, String nonce) throws AesException
{
try {
String[] array = new String[] { token, timestamp, nonce};
StringBuffer sb = new StringBuffer();
// 字符串排序
Arrays.sort(array);
for (int i = 0; i < 3; i++) {
sb.append(array[i]);
}
String str = sb.toString();
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.ComputeSignatureError);
}
}
}
4.自定义异常类
public class AesException extends Exception {
public final static int OK = 0;
public final static int ValidateSignatureError = -40001;
public final static int ParseXmlError = -40002;
public final static int ComputeSignatureError = -40003;
public final static int IllegalAesKey = -40004;
public final static int ValidateAppidError = -40005;
public final static int EncryptAESError = -40006;
public final static int DecryptAESError = -40007;
public final static int IllegalBuffer = -40008;
private int code;
private static String getMessage(int code) {
switch (code) {
case ValidateSignatureError:
return "签名验证错误";
case ParseXmlError:
return "xml解析失败";
case ComputeSignatureError:
return "sha加密生成签名失败";
case IllegalAesKey:
return "SymmetricKey非法";
case ValidateAppidError:
return "appid校验失败";
case EncryptAESError:
return "aes加密失败";
case DecryptAESError:
return "aes解密失败";
case IllegalBuffer:
return "解密后得到的buffer非法";
default:
return null; // cannot be
}
}
public int getCode() {
return code;
}
public AesException(int code) {
super(getMessage(code));
this.code = code;
}
}
- 配置:
进入开发者的小程序中,进入开发—>开发管理—>开发设置,找到消息推送进行配置
URL需要填写完整,http或https加上域名再加上我们controller的请求路径(/wechat/signature/check)
Token只有和服务器Service里面使用SHA1时传入的token参数一致才会验证成功
EncodingAESKey随机生成即可
推荐使用兼容加密模式和json数据格式