avatar

麦兜的小站

MDO.INK

  • 首页
  • 随笔
  • 知识库
  • 归档
  • 动态
  • 标签
  • 关于
Home 手机扫描二维码后关注公众号,发送验证码给公众号,公众号返回验证码,然后输入到网页判断
文章

手机扫描二维码后关注公众号,发送验证码给公众号,公众号返回验证码,然后输入到网页判断

Posted 2025-06-21 Updated 2025-06- 21
By power 已删除用户
24~31 min read

一、业务需求

手机扫描二维码后关注公众号,发送验证码给公众号,公众号返回验证码,然后输入到网页判断验证码是否正确后通过登录。

二、初步接入微信公众号

接入微信公众平台开发,开发者需要按照如下步骤完成:

  • 1、填写服务器配置

  • 2、验证服务器地址的有效性

  • 3、依据接口文档实现业务逻辑

2.1 填写服务器配置

登录微信公众平台官网后,在公众平台官网的开发-基本设置页面,勾选协议成为开发者,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件的接口URL。Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。

同时,开发者可选择消息加解密方式:明文模式、兼容模式和安全模式。。加解密方式的默认状态为明文模式,选择兼容模式和安全模式需要提前配置好相关加解密代码。

2.2 验证服务器地址有效性

开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:

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

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

1)将token、timestamp、nonce三个参数进行字典序排序

2)将三个参数字符串拼接成一个字符串进行sha1加密

3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

2.2.1 验证消息的确来自微信服务器 - 代码

token值要与配置服务器时的token一致

我们采取明文模式,不需要encrypt密文参数

signature与sha1加密后的token、timestamp、nonce 进行对比,成功则返回echostr,成为开发者。

private static final String token = "ShiShuoMing";

@GetMapping("callback")
public String callback(@RequestParam("signature") String signature,
                       @RequestParam("timestamp") String timestamp,
                       @RequestParam("nonce") String nonce,
                       @RequestParam("echostr") String echostr) {
    log.info("get验签请求参数:signature:{},timestamp:{},nonce:{},echostr:{}",
            signature, timestamp, nonce, echostr);
    String shaStr = SHA1.getSHA1(token, timestamp, nonce, "");
    if (signature.equals(shaStr)) {
        return echostr;
    }
    return "unknown";
}

2.2.2 SHA1 加密

@Log4j2
public class SHA1 {

    /**
     * 用SHA1算法生成安全签名
     *
     * @param token     票据
     * @param timestamp 时间戳
     * @param nonce     随机字符串
     * @param encrypt   密文
     * @return 安全签名
     */
    public static String getSHA1(String token, String timestamp, String nonce, String encrypt) {
        try {
            String[] array = new String[]{token, timestamp, nonce, encrypt}
            StringBuffer sb = new StringBuffer()
            // 字符串排序
            Arrays.sort(array)
            for (int i = 0
                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
                shaHex = Integer.toHexString(digest[i] & 0xFF)
                if (shaHex.length() < 2) {
                    hexStr.append(0)
                }
                hexStr.append(shaHex)
            }
            return hexStr.toString()
        } catch (Exception e) {
            log.error("sha加密生成签名失败:", e)
            return null
        }
    }
}

2.2.3 内网穿透

在第一步配置服务器时,除了签名token还需要填写URL,当微信服务器会向URL发送get请求,当验签通过后,我们才可以成为开发者,拥有权限(向用户发送消息等等)。

由于开发环境不方便调试,所以就需要用到natapp内网穿透技术了,把本地ip映射到外网域名地址。

使用natapp进行内网穿透,配置如下:

配置完成后,会得到authtoken, 之后在natapp.exe的文件目录下,cmd输入start natapp -authtoken=xxxx启动,就可以把本地url地址映射到外网。

以测试号为例,此时URL地址就为:

能够成功填写接口配置信息就代表我们已经成为了开发者(提交信息时,微信服务器会发送请求验签),用户向公众号发送消息时。

2.3 接收普通消息(接收消息、关注、取关等) -- 初探

公众号方收到的消息发送者是一个OpenID,是使用用户微信号加密后的结果,每个用户对每个公众号有一个唯一的OpenID。

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上(还是callback接口)。

请注意:

  1. 关于重试的消息排重,推荐使用msgid排重。
  2. 微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。详情请见“发送消息-被动回复消息”。
  3. 如果开发者需要对用户消息在5秒内立即做出回应,即使用“发送消息-被动回复消息”接口向用户被动回复消息时,可以在

公众平台官网的开发者中心处设置消息加密。开启加密后,用户发来的消息和开发者回复的消息都会被加密(但开发者通过客服接口等API调用形式向用户发送消息,则不受影响)。关于消息加解密的详细说明,请见“发送消息-被动回复消息加解密说明”。 各消息类型的推送XML数据包结构如下:

文本消息格式

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[fromUser]]></FromUserName>
  <CreateTime>1348831860</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[this is a test]]></Content>
  <MsgId>1234567890123456</MsgId>
  <MsgDataId>xxxx</MsgDataId>
  <Idx>xxxx</Idx>
</xml>

| 参数 | 描述 | | --- | --- | | ToUserName | 开发者微信号 | | FromUserName | 发送方账号(一个OpenID) | | CreateTime | 消息创建时间 (整型) | | MsgType | 消息类型,文本为text | | Content | 文本消息内容 | | MsgId | 消息id,64位整型 | | MsgDataId | 消息的数据ID(消息如果来自文章时才有) | | Idx | 多图文时第几篇文章,从1开始(消息如果来自文章时才有) |

参数解读:

  • @requestBody: 请求的消息体会放到requestBody里
  • @msg_signature: 开启加密模式时,post请求还会发送meg_signature消息用于验签,明文时不会发送
@PostMapping(value = "callback", produces = "application/xml;charset=UTF-8")
public String callback(
        @RequestBody String requestBody,
                       @RequestParam("signature") String signature,
                       @RequestParam("timestamp") String timestamp,
                       @RequestParam("nonce") String nonce,
                       @RequestParam(value = "meg_signature", required = false) String msgSignature) {
    log.info("接收到微信的请求:request:{}, signature:{},timestamp:{},nonce:{}", requestBody, signature, timestamp, nonce);
    return "unknown";
}

2.5 回复消息 -- 初探

我们希望当用户关注后,为用户发送验证码。同样,也应该以XML形式发送,我们要得到两个参数:

ToUserName:发给谁

FromUserName:来自哪(公众号)

回复文本消息格式

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[fromUser]]></FromUserName>
  <CreateTime>12345678</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[你好]]></Content>
</xml>

| 参数 | 是否必须 | 描述 | | --- | --- | --- | | ToUserName | 是 | 接收方账号(收到的OpenID) | | FromUserName | 是 | 开发者微信号 | | CreateTime | 是 | 消息创建时间 (整型) | | MsgType | 是 | 消息类型,文本为text | | Content | 是 | 回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示) |```less @PostMapping(value = "callback", produces = "application/xml;charset=UTF-8") public String callback( @RequestBody String requestBody, @RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce, @RequestParam(value = "meg_signature", required = false) String msgSignature) { log.info("接收到微信的请求:request:{}, signature:{},timestamp:{},nonce:{}", requestBody, signature, timestamp, nonce);

Map<String, String> msgMap = MessageUtil.parseXml(requestBody);
String toUserName = msgMap.get("ToUserName"); 
String fromUserName = msgMap.get("FromUserName"); 

String msg = "<xml>n" +
        "  <ToUserName><![CDATA[" + fromUserName + "]]></ToUserName>n" +
        "  <FromUserName><![CDATA[" + toUserName + "]]></FromUserName>n" +
        "  <CreateTime>12345678</CreateTime>n" +
        "  <MsgType><![CDATA[text]]></MsgType>n" +
        "  <Content><![CDATA[你好,欢迎来到坤坤Club]]></Content>n" +
        "</xml>";

return msg;

}

```

知识库
License:  CC BY 4.0
Share

Further Reading

Jul 31, 2025

如何实现接口幂等性

通俗的说,用户在系统中有操作,不管重复多少次,都应该产生一样的效果或返回一样的结果的。 幂等性的概念 幂等(Idempotent)是一个数学与计算机学的概念,常见于抽象代数中。 f(n)=1^n//无...

Jul 19, 2025

10个npm工具包

有了npm之后,前端人员真的是过上好日子了。我们可以直接把别人写好的工具包拿来用,非常的方便。 1.day.js-轻量日期处理 npminstalldayjs importdayjsfrom'd...

Jul 17, 2025

How to set up PHP7.4 on MacOS.

Thisisallverywellandgood.Apartfromonesmallinsignificantthing… TheversionofPHPinuseiscurrently7.4. Th...

OLDER

公众号 接收手机验证码发送给用户

NEWER

ubuntu文件夹建立软链接方法

Recently Updated

  • 如何实现接口幂等性
  • 10个npm工具包
  • How to set up PHP7.4 on MacOS.
  • Automa:一键自动化,网页数据采集与工作流程优化专家Automa:解锁自动化
  • Mac 下用 brew 搭建 LNMP

Trending Tags

thinkphp clippings

Contents

©2025 麦兜的小站. Some rights reserved.

Using the Halo theme Chirpy