它俩的验证方法其实差别不大,就是一个参数的差别。

官方文档

微信公众号官方文档的验证说明:

链接:接入概述 | 微信开放文档 (qq.com)
开发者提交信息后,微信服务器将发送 GET 请求到填写的服务器地址 URL 上,GET请求携带参数如下表所示:

signature:微信加密签名,signature结合了开发者填写的 token 参数和请求中的 timestamp 参数、nonce参数。
timestamp:时间戳
nonce:随机数
echostr:随机字符串

开发者通过检验 signature 对请求进行校验(下面有校验方式)。
若确认此次 GET 请求来自微信服务器,请原样返回 echostr 参数内容,则接入生效,成为开发者成功,否则接入失败。

加密/校验流程如下:

1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与 signature 对比,标识该请求来源于微信

而企业微信的是这样的:

链接:回调配置 - 接口文档 - 企业微信开发者中心 (qq.com)
假设企业的接收消息的URL设置为http://api.3dept.com。
企业管理员在保存回调配置信息时,企业微信会发送一条验证消息到填写的URL,请求内容如下:
请求方式:GET
请求地址:http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS&timestamp=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搭一个简单的服务器即可。

最后修改:2022 年 05 月 23 日
如果觉得我的文章对你有用,请随意赞赏