你敢信?微信订阅号也能做扫码登录!大多数人都不知道的黑科技

个人订阅号实现微信登录

首先我们聊一聊登录,传统的登录无非就是输入用户名密码进行登录,相信有很多小伙伴还在这样去做,为什么呢?

因为这样简单,用户名密码登录零成本,但是随着手机的依赖性不断增加,这种方式的弊端也逐渐显露出来,不知道各位小伙伴怎么想,我是经常记不住密码,有时候账号都不记得了,现在各大网站基本都是扫码登录、手机号登录

而这两种方式,对于我们初学者来说,成本就比较高了,都不好接入

首先手机号登录,要发短信,肯定是要花钱的,而且流程还比较麻烦

扫码登录应用比较多,但是也会有依赖性,首先那是各大应用的扫码登录,比如百度、百度网盘、CSDN之类的,要进行扫码登录,就必须要下载对应的APP,CSDN放我手机里800年不用了,当然也有很多都支持微信登录,微信就不在多说了吧,微信的生态,每个人现在都离不开了

那么微信扫码登录呢?

首先我很遗憾的告诉大家,在微信官方文档中个人订阅号不支持微信网页授权,看下图

image-20250923165451581

image-20250923165531456

如果想要实现微信网页授权,前提就是必须注册服务号,而且通过微信认证,一年300大洋,而且服务号需要营业执照

那我们个人申请的订阅号能不能实现微信扫码登录呢?

答案是能,只不过此扫码非彼扫码,通过一种迂回的方式实现

首先我们介绍一下微信体系中的openId、unionId是怎么个事

首先我们只要在微信体系中开发,有一个appid是离不开的,不论你是做公众号、还是小程序,或者是APP、网站,都是离不开的,那有很多小伙伴就会问了,APP,网站跟微信扯不上关系,为什么呢?

是的,你只是开发网站、APP可以的,但是你要用微信的功能,比如扫码登录、微信支付、分享朋友圈等功能,那就必须按微信的节奏走

小程序、公众号注册之后就会有appid,对于网站、APP就需要你在微信开放平台就绑定,如下图

image-20250926140531910

绑定之后就会给你分配appid

image-20250926140710688

那么什么是openid、unionid呢

openid就是对于某个应用,微信为开发者对于用户起的唯一id

说的有点绕,举例子:比如你给公众号发了私信,公众号的开发者就能获取到openid,代表的是你这个微信用户,而且以后你给这个公众号发消息,他获取到的openId都是同一个

微信给开发者的不是我们的真实微信资料,而是一个openid

那什么是unionid呢?

小白现在运营了一个小程序、一个网站,我已经将两个应用在开放平台绑定,那用户在小程序进行微信登录,在网站进行微信登录,对于同一个用户,我会拿到两个openId,但是在网站后台、小程序后台拿到的unionid是一样的

好了,言归正传

既然了解了这种机制,那我们就可以使用消息的方式实现订阅号的微信登录

官方网站:https://developers.weixin.qq.com/doc/subscription/guide/product/message/Receiving_standard_messages.html

微信公众号的消息机制,默认注册后,开发者可以在微信公众平台配置自动回复,当我们验证开发者服务器后,微信会将用户的消息转发到我们配置好的服务器,格式为xml,就是说你在java服务端可以拿到用户对你公众号发送的消息内容,并且可以进行回复

image-20250926142245529

<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开始(消息如果来自文章时才有)

我们可以看到,微信会将上述字段内容转发到我们的服务器

我们先说一下思路

1、首先,我们将公众号二维码放置在登录界面,提示用户扫码关注公众号,在后台回复“登录”获取验证码,用户发送“登录”给公众号。

2、服务端拿到消息内容,判断如果是“登录”,随机生成一个唯一的6位数的验证码(短暂唯一),3分钟有效,三分钟内唯一即可,然后将code、openId存储到redis,可以存一对,code:openId,openId:code,然后将6位数验证码返回给用户。

3、用户拿到验证码在网页上输入后,点击登录,此时服务端只能拿到code,根据code查询redis获取openid、如果能查到,在根据查到的openid查询code,如果验证通过,则登陆成功

这是一种巧妙的方式,公众号接收发送消息的权限订阅号有权限

下面我们就来实战

环境要求:首先你要做一个内网穿透,可以自己租服务器、也可以使用netapp等工具

目的是将你本地的服务暂时连通到公网,供微信服务器调用,因为微信会将用户发送的消息转发到开发者服务器,我们本地开发,在局域网,微信调不到我们的服务

小白有一个月的体验额度,就用第一种了

1、在你的服务器上安装个工具,frp

服务器安全组开放两个端口:40001、8088

image-20250926151033158

下载地址:https://github.com/fatedier/frp/releases

下载后传到服务器并解压

image-20250926145559746

[root@iZ2ze6y8dmewokrjlilbngZ frp_0.63.0_linux_amd64]# ll
total 34344
-rwxr-xr-x 1 1001 docker 15425688 Jun 25 12:10 frpc
-rw-r--r-- 1 1001 docker      142 Jun 25 12:14 frpc.toml
-rwxr-xr-x 1 1001 docker 19714200 Jun 25 12:10 frps
-rw-r--r-- 1 1001 docker       16 Jun 25 12:14 frps.toml
-rw-r--r-- 1 1001 docker    11358 Jun 25 12:14 LICENSE
[root@iZ2ze6y8dmewokrjlilbngZ frp_0.63.0_linux_amd64]#

修改frps.toml

# 绑定端口
bindPort = 40001
# 认证token,需要与frpc保持一致
auth.token = "xiaobai"

# webui
# 默认为 127.0.0.1,如果需要公网访问,需要修改为 0.0.0.0。
webServer.addr = "0.0.0.0"
webServer.port = 40002
# dashboard 用户名密码,可选,默认为空
webServer.user = "xiaobai"
webServer.password = "xiaobai"

修改frpc.toml

serverAddr = "127.0.0.1"
serverPort = 40001
# 认证token,需要与frpc保持一致
auth.token = "xiaobai"
# transport.tls.enable=false

webServer.addr = "0.0.0.0"
webServer.port = 4000


# frpc.toml
[[visitors]]
name = "weixin-proxy"
type = "stcp"
serverName = "weixin-proxy"
secretKey = "xiaobai"
bindAddr = "0.0.0.0"
bindPort = 8088

启动

nohup ./frps -c frps.toml > frps.log 2>&1 &
nohup ./frpc -c frpc.toml > frpc.log 2>&1 &

image-20250926151241456

2、在你的windows安装frp,下载地址同上,下载同版本,选择windows平台的

image-20250926151147897

编辑frpc.toml

# frps端的ip
serverAddr = "wwww.xbjava.com"
# frps端的port
serverPort = 40001
# 认证token,需要与frpc保持一致
auth.token = "xiaobai"

webServer.addr = "0.0.0.0"
webServer.port = 4000

[[proxies]]
name = "weixin-proxy"
type = "stcp"
secretKey = "xiaobai"
localIP = "127.0.0.1"
localPort = 8080

打开cmd,执行

frpc.exe -c frpc.toml

image-20250926151223330

解释一下,当访问公网wwww.xbjava.com的8088端口时,实际访问的是我们本地的8080端口,做了一层代理转发

所以我们的java项目要运行在8080端口

2、申请微信公众号测试

https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

image-20250926152112512

3、配置文件配置

image-20250926152523048

4、编写微信服务器验证接口

这一步的目的是让微信信任我们的服务器,简单描述一下,这一步就是说你配置一个你的服务器地址,微信会调用你的地址,并且给你传一堆加密参数,你以指定的格式解密,判断消息是不是来自于微信,想当于开发者跟微信服务器达成一种协议,验证通过后,微信会把用户的消息转发给你。

注意:这是个GET请求,用作服务器验证,通过后微信会将用户消息以POST请求转发给你的服务器,也是这个URL

参考官方文档:https://developers.weixin.qq.com/doc/service/guide/dev/push/

// 微信服务器验证
@GetMapping("/callback")
public String validateServer(@RequestParam("signature") String signature,
                             @RequestParam("timestamp") String timestamp,
                             @RequestParam("nonce") String nonce,
                             @RequestParam("echostr") String echostr) {
    String token = weChatProperties.getToken();
    String[] arr = {token, timestamp, nonce};
    Arrays.sort(arr);
    String content = String.join("", arr);
    String sha1 = DigestUtils.appendMd5DigestAsHex(content.getBytes(StandardCharsets.UTF_8), new StringBuilder()).toString();
    // 注意:微信要求是 SHA1,这里示例用 Spring 的工具展示流程,生产请替换为真正的 SHA1
    // 返回 echostr 代表验证通过
    return echostr;
}

5、启动项目开始验证

image-20250926153254165

6、验证成功

image-20250926153316855

7、编写接收消息接口

同样的接口URL,POST请求,当我关注测试号,发送你好,微信会将消息转发给服务器,如下是消息内容

注意,接收到消息之后,处理完回复指定文本,或者回复空串,否则微信服务器会重试,可以根据msgid进行消息排重

官网地址:https://developers.weixin.qq.com/doc/subscription/guide/product/message/Receiving_standard_messages.html

image-20250926154150253

8、编写登录逻辑

// 接收用户关注/消息事件:当接收到包含 openId 的 XML(如关注或发送“登录”)
@PostMapping("/callback")
public String onMessage(HttpServletRequest request) throws Exception {
    String xml = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
    // 极简解析 openId
    String openId = parseXmlByTagName(xml, "FromUserName");
    // 解析用户内容
    String content = parseXmlByTagName(xml, "Content");
    if ("登录".equals(content)) {
        // 用户是进行登录
        // 生成验证码
        String code = generateSixDigitCode();
        // 保存到 Redis,5 分钟过期
        String userKey = "login:code:" + openId;
        String idxKey = "login:code:idx:" + code;
        redisTemplate.opsForValue().set(userKey, code, 5, TimeUnit.MINUTES);
        redisTemplate.opsForValue().set(idxKey, openId, 5, TimeUnit.MINUTES);
        // 将验证码返回给用户
        return code;
    } else {
        // 执行其他有需要的业务逻辑
    }
    // 按微信协议必须返回空串或固定文本,避免重复推送
    return "";
}

登录验证

// 接收用户关注/消息事件:当接收到包含 openId 的 XML(如关注或发送“登录”)
@PostMapping("/callback")
public String onMessage(HttpServletRequest request) throws Exception {
    Map<String, String> stringStringMap = parseWxReceiveMessageAsMap(request);
    // 极简解析 openId
    String openId = stringStringMap.get("FromUserName");
    // 解析用户内容
    String content = stringStringMap.get("Content");
    if ("登录".equals(content)) {
        // 用户是进行登录
        // 生成验证码
        String code = generateSixDigitCode();
        // 保存到 Redis,5 分钟过期
        String userKey = "login:code:" + openId;
        String idxKey = "login:code:idx:" + code;
        redisTemplate.opsForValue().set(userKey, code, 5, TimeUnit.MINUTES);
        redisTemplate.opsForValue().set(idxKey, openId, 5, TimeUnit.MINUTES);
        // 将验证码返回给用户
        return buildTextMessageReply(code, stringStringMap);
    } else {
        // 执行其他有需要的业务逻辑
    }
    // 按微信协议必须返回空串或固定文本,避免重复推送
    return "";
}

9、开发前端页面

image-20250926155047104

10、测试

先随便输一个

image-20250926162709014

正确的

image-20250926162757148

大功告成

把登录功能接入你的网站,用户每次扫码登录就ok了,不需要在输入用户名密码进行登录了

后续逻辑分析

其实对于我们网站来讲,并不需要知道用户的用户名是啥,并不重要,主要的是能够确定用户的合法性即可,用户登录后再网站可以进行相关操作即可,重要的是快捷,方便

当然如果已经做了用户名登录的也不要大改,可以做两种登录方式,将openid与用户进行绑定即可实现两种登录方式

说明一下,本次用的是测试账号,如果是真实账号,位置如下:

友情提示:启用服务器配置后,公众平台配置的自动回复、自定义菜单均失效,请知悉!

原因是启用了服务器配置,自定义菜单均可以通过api去配置,关于自动回复小白还想说两句,公众平台上限200条,公众平台上限200条,公众平台上限200条

image-20250926163504323

今天的分享就到这里,感谢你的认真阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈小白.

感谢老板,祝老板今年发大财!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值