基于 Java Spring Security 的关注微信公众号即登录的设计与实现 ya

太长不看版本

本文通过一个实际的具有一定商业价值的项目,展示了 API 优先的开发方法。通过薅羊毛的方式,落地了 Free Arch 架构。

背景和价值

通过微信公众号积累粉丝并进行商业活动宣传,是新媒体运营的常见方式。而系统对接微信登录,既能给用户带来便利,同时也能够给系统引流。但是传统或者标准的 PC 网页端微信扫码登录,用户扫码只需要做 OAuth 授权,不必关注公众号。但是对于运营者来说,更希望通过微信登录的用户,自动成为微信粉丝,实现系统中微信用户和公众号粉丝的一一对应。

所以,关注公众号即登录,将系统的微信用户和公众号粉丝等同起来,方便了运营同学。

另外,传统的微信扫码登录,需要在公众平台之外,额外再在开发平台申请一个应用,再和公众号做绑定,多了一个账号,就多了一份维护工作,增加了管理者的心智负担,还要多花钱,毕竟两个不同的账号需要单独缴费和认证。

以及,开发平台和公众平台的 openid 不一样,还需要通过 unionid 的机制做关联,增加了开发的心智负担和开发成本。

以上,通过关注公众号即登录的方案,都可以避免,和微信打交道的全程只需要 openid 即可。

Java Spring-Security

Spring Security 是一个专注在 Java 应用中提供认证和授权的框架。和所有 Spring 项目一样,Spring Security 的真正威力在于其极易扩展已满足定制化的需求,为认证和授权提供完整的和可扩展的支持。

Open API

Open API 即开放 API,也成为开放平台。它是服务型网站常见的一种应用,网站的服务商将自己的网站服务封装成一系列 API 开放出去,供第三方开发者使用,这种行为就叫做开放网站的 API,所开放的 API 就被称作 Open API。

Open API 规范始于 Swagger 规范,经过 Reverb Technologies 和 SmartBear 等公司多年的发展,Open API 计划拥有该规范。规范是一种与语言无关的格式,用于描述 Web 服务,应用程序可以解释生成的文件,这样才能生成代码、生成文档并根据其描述的服务创建模拟应用。

Swagger 的目标是为 API 定义一个标准的,与语言无关的接口,使人和计算机在看不到源码或者看不到文档或者不能通过网络流量检测的情况下能够发现和理解各种服务的功能。当服务通过 Swagger 定义,消费者通过少量的实现逻辑就能与远程服务互动。类似于低级编程接口,Swagger 去掉了调用服务时的很多猜测。

关注公众号即登录的流程设计

PC 网页站点实现微信登录时,需要通过用户使用微信扫描网页上展示的二维码,然后在手机上的微信授权登录。如何实现二维码的展示,并“感知”用户扫描事件,是需要解决的关键问题。传统的 OAuth 微信扫码登录,由于本质上是打开了一个微信官方的页面,因此不需要关注这其中的细节,但是不通过打开微信官方的页面,就需要自行设计这个展示和感知的能力了。

常规 PC 网页端微信扫码登录,PC 打开了微信官方的页面,由微信官方展示二维码,而手机扫描后,会在微信端跳出授权页面,用户确认后,微信官方二维码页面会重定向至开发者在开放平台设置好的回调页面,并将临时授权码作为查询字符串;而关注公众号即登录,则利用了微信的带参二维码功能,用户扫描这种二维码后,手机微信会展示开发者的微信公众号,同时将用户信息(主要是 openid)通过服务器端 API 调用,发送给开发者服务器。该过程没有二次确认,对于已关注过公众号的用户,直接发送扫描事件;对于新用户,需要新用户点击关注,才会发送该事件。这里的难点在于如何感知用户的扫描事件,以及保证服务器端 API 调用的安全(主要是确认调用者真的是来自微信而不是伪造的请求)。

下面通过阐述利用微信的带参二维码,通过接收微信服务器发送的消息来“感知”用户的扫描事件。首先是带参二维码的生成,它是通过调用微信官方的接口完成的。 微信公众平台提供了两种生成带参数二维码的接口,分别是一、临时二维码,有 过期时间,数量没有明确的上限;二、永久二维码,没有过期时间,但是最多只能生成 10 万个。显然,对于登录场景,适合采用临时二维码。本文的方案里, 过期时间设置为 1 分钟。如果用户在打开登录页面的 1 分钟内,都没有扫码,或者因为网络等原因扫码失败,那么就展示二维码过期,提示用户刷新二维码,这个体验和用户登录电脑版微信相似。其中调用生成二维码接口的关键是需要传递场景值,每个场景值会和一个尝试登录的请求相关,因此必须做到唯一。本文选择使用 UUID(或者称为 GUID)。UUID 由 128 位数字组成,其生成算法保证了 其极低的重复率,具体地说,如果以一秒钟生成十亿个 UUID 的速度连续生成一年,才会有 50%的机会产生一个重复 ID。下图为未登录用户成功扫码登录系统的流程图。

由上图可以看出,开发者服务为尝试登录请求生成场景值后,会同时传递给微信服务和浏览器。这个场景值还会被后续查询用户扫描状态时被使用。如果用户不扫描,致使二维码过期,那么这个场景值将会被丢弃,被认为该尝试登录失败。从上图还可以看出,当用户扫描后,微信会自动进入开发者公众号页面,这为运营提供了很大的好处,因为公众号页面会展示历史图文信息,相比传统的用 户扫码后,展示的信息要丰富得多。另外可以看到,无论用户是否关注过公众号, 扫码后,微信服务都会向开发者服务推送用户的 openid 以及场景值。而且对于没有关注过公众号的新用户,还会自动关注,成为公众号新粉丝。这样就把系统 的微信用户账号和微信公众号分析的属性关联了起来。场景值被系统用来更新扫码状态,而 openid 用来关联或者创建账号。这一系列动作完成后,系统还可以通 过微信渠道向用户发送自定义的欢迎信息,这是传统微信登录方式很难做到的 (需要实现模板消息功能,但是模板消息的使用是受到严格监控和限制的,而在扫码后的消息回复则不受此限)。

其次是扫码状态的更新,当开发者服务器收到微信服务生成的二维码后,就 处于等待用户扫码的阶段,当收到微信服务通知用户扫码成功或者超时,开发者服务器应该通知用户端。因此这里需要一个即时消息服务。其状态转移如下图所示,一共有三种状态:一、扫码成功,收到微信服务通知的用户 openid,场景值;二、扫码失败,收到微信服务通知的失败原因;三、扫码超时,一段时 间没有收到微信服务的通知。

开发者服务器端接收到微信服务通知或者超时后,需要通知客户端,一般有 三种技术方案,即轮询、长连接以及 Socket IO。由于普通轮询为了保持实时性, 会在短时间内发送大量的 HTTP 请求,不可取。而 Socket IO 实现较复杂,并且对服务器资源消耗过大,因此长连接方案是最适合的。在这种方案下,客户端向服务器端发送请求询问扫码状态,服务器只在扫码成功或者超时的情况下给予回应,其他情况会挂起连接。因此在超时前,一个客户端只会向服务器端发送一个查询请求,有效地减轻了服务器端连接压力。这里开发者服务会接受到客户端查询扫码状态和微信服务通知扫码结果的 HTTP 请求,两个请求到达的次序有可能 不同,在实现时需要注意。下面给出时序图:

从上面的时序图可以看出,只需要对情况一进行查询请求的挂起。另外,向客户端返回扫码结果后,一定要将缓存记录清除,一方面更加安全,对重放的请求,因为查询不到扫码记录会直接回复超时;另一方面,可以及时释放内存,节省不必要的资源开销。由于生产环境往往不止单个应用实例,扫码状态需要缓存在独立于应用的缓存服务中,后续查询请求即使被另外的应用实例处理,也能返回正确的状态。当开发者服务收到扫码成功的结果后,就可以将微信的 openid 作 为第三方登录的 id,与自己的用户数据库中的用户做关联了。由于采用了关注公 众号即登录的流程,不再额外需要申请和维护微信开放平台账号,也不再需要处理 unionid 的映射。

本节通过仔细研究微信公众号的开放 API 能力,梳理了一套非常规的微信扫码登录方案,通过严谨分析客户端、开发者服务和微信服务三者间的 HTTP 沟通时序,实现了对用户微信扫码的感知能力,为最终实现关注公众号即登录打下了可行性基础。

应用架构设计

rch 架构。

演示应用架构图大致如下

即通过 Cloudflare,使用免费的网络防火墙服务。对于要实现的 Java Spring-Security 应用,部署在 Heroku 这个 PaaS 平台上,也是免费的。对于微信服务,我们使用微信官方提供的测试号,也是免费的。但是对于测试公众号,有个限制是只能有 100 个关注者。但是对于演示来说足够用了,相信本文的阅读量不会超过 100,如果超过,甚至还有打赏,产生了收入,那我就去注册一个真正的公众号!

在流程设计上提到对于扫码状态的查询,需要长链接以等待微信消息通知,至于微信发过来的消息存储方面,可以采用 Redis,也可以使用消息队列。对于 Redis 方案,也有对应的免费服务,但是本文采用了消息队列来实现,消息队列使用了 Pulsar,跟上时代。Pulsar 号称是下一代的消息队列方案,比 Kafka 有过之而无不及。

API first 开发方式

应用程序向云环境这一演变趋势为更好地集成服务和增加代码重用提供了机会,只要拥有一个接口,然后通过该接口,其他服务的应用程序就可以与你的应用程序进行交互,这是向其他人公开你的功能,但是,开发 API 不应该是在开发后才公开功能。

API 文档应该是构建应用程序的基础,这个原则正式 API first 开发的全部内容。你需要设计和创建描述新服务与外部世界之间交互的文档,一旦建立了这些交互,就可以开发代码逻辑来支持这些交互。它的好处是:

  • 团队在开发过程中更快地开始彼此交互。API 文档是应用程序与使用它的人之间的合同。

  • 内部开发可以在 API 合同背后进行,而不会干扰使用它的人的努力,计划使用你的应用程序的团队可以使用 API 规范来了解如何与你的应用程序进行交互,甚至在开发前,他们还可以使用文档创建用于测试其他应用程序的虚拟服务。

基于 Java

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

倾听铃的声

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值