它俩的验证方法其实差别不大,就是一个参数的差别。
官方文档
微信公众号官方文档的验证说明:
代码语言:txt复制链接:接入概述 | 微信开放文档 (qq.com)
开发者提交信息后,微信服务器将发送 GET 请求到填写的服务器地址 URL 上,GET请求携带参数如下表所示:
signature:微信加密签名,signature结合了开发者填写的 token 参数和请求中的 timestamp 参数、nonce参数。
timestamp:时间戳
nonce:随机数
echostr:随机字符串
开发者通过检验 signature 对请求进行校验(下面有校验方式)。
若确认此次 GET 请求来自微信服务器,请原样返回 echostr 参数内容,则接入生效,成为开发者成功,否则接入失败。
加密/校验流程如下:
1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与 signature 对比,标识该请求来源于微信
而企业微信的是这样的:
代码语言:txt复制链接:回调配置 - 接口文档 - 企业微信开发者中心 (qq.com)
假设企业的接收消息的URL设置为http://api.3dept.com。
企业管理员在保存回调配置信息时,企业微信会发送一条验证消息到填写的URL,请求内容如下:
请求方式:GET
请求地址:http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323&echostr=ENCRYPT_STR
参数说明:
msg_signature:企业微信加密签名,msg_signature计算结合了企业填写的token、请求中的timestamp、nonce、加密的消息体。
timestamp:时间戳。与nonce结合使用,用于防止请求重放攻击。
nonce:随机数。与timestamp结合使用,用于防止请求重放攻击。
echostr:加密的字符串。需要解密得到消息内容明文,解密后有random、msg_len、msg、receiveid四个字段,其中msg即为消息内容明文
回调服务需要作出正确的响应才能通过URL验证,具体操作如下:
1. 对收到的请求,解析上述的各个参数值(参数值需要做Urldecode处理)
2. 根据已有的token,结合第1步获取的参数timestamp, nonce, echostr重新计算签名,然后与参数msg_signature检查是否一致,确认调用者的合法性。
3. 解密echostr参数得到消息内容(即msg字段)
4. 在1秒内响应GET请求,响应内容为上一步得到的明文消息内容(不能加引号,不能带bom头,不能带换行符)
差别概括
相同点
同样是4个参数:msg_signature(signature)、timestamp、nonce、echostr。
同样的请求方式:GET
不同点
计算签名不同
公众号验证回调,token、timestamp、nonce排序并SHA1计算签名并与signature对比。
企业微信应用验证回调,token、timestamp、nonce、echostr排序并SHA1计算签名并与signature对比。
也就是说计算签名时公众号的要比企业微信应用少加一个echostr
返回数据不同
公众号验证回调,直接返回echostr的内容即可。
企业微信应用验证回调,返回的内容需要解密echostr得到。
回调校验代码编写 - Java
微信官方提供了示例代码,企业微信应用回调验证代码只需要稍加修改即可给微信公众号使用。
ps. 微信公众号提供的验证示例代码其实是照抄企业微信应用的,直接用不行,需要改改。
下载企业微信的示例代码,打开WXBizMsgCrypt.java
,复制函数VerifyURL
进行修改,将新函数命名为VerifyAPI
:
- 原函数
/**
* 验证URL
* @param msgSignature 签名串,对应URL参数的signature
* @param timeStamp 时间戳,对应URL参数的timestamp
* @param nonce 随机串,对应URL参数的nonce
* @param echoStr 随机串,对应URL参数的echostr
*
* @return 校验成功返回解密结果
* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
*/
public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
throws AesException {
String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
if (!signature.equals(msgSignature)) {
throw new AesException(AesException.ValidateSignatureError);
}
String result = decrypt(echoStr);
return result;
}
- 新函数
/**
* 验证API
* @param msgSignature 签名串,对应URL参数的signature
* @param timeStamp 时间戳,对应URL参数的timestamp
* @param nonce 随机串,对应URL参数的nonce
* @param echoStr 随机串,对应URL参数的echostr
*
* @return 校验成功返回echostr
* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
*/
public String VerifyAPI(String msgSignature, String timeStamp, String nonce, String echoStr)
throws AesException {
String signature = SHA1.getSHA1(token, timeStamp, nonce, "");
if (!signature.equals(msgSignature)) {
throw new AesException(AesException.ValidateSignatureError);
}
String result = echoStr;
return result;
}
然后用SpringBoot搭一个简单的服务器即可。