小程序登录与OAuth规范

登录认证是一个完整应用必备的模块,除非你的应用程序不需要任何与用户相关的功能 比如hao123 这种静态导航网站一般不会涉及用户体系。

很多人在最初接触小程序登录功能时,会误认为以微信为入口的小程序使用微信登录,是一件理所当然、毫不费力的事儿,这是错误地将小程序理解成了微信的一部分。

小程序和微信是一种类似应用与平台的关系,小程序属于微信公众平台,同一个平台下还有微信公众号:

  • 在技术角度上,小程序与微信的关系比公众号更密切,因为公众号的文章本质上是一个 H5 网页,对微信底层的依赖比小程序弱;
  • 从产品角度上,二者与微信的关系一致,都是运行在微信平台上的第三方应用。

既然小程序是微信平台的第三方应用,那么在接入微信登录时就要严格遵守官方的接入规范。
而在互联网技术领域,对于支持第三方应用接入的平台,在登录授权上有一套标准的技术规范:OAuth 2.0。

OAuth 2.0 学起来比较枯燥,所以先从最容易理解的小程序登录流程讲起,理解其中涉及的各种术语之后,再理解 OAuth 2.0 规范就容易多了。

如何搭建微信小程序的登录流程?

我们认为以微信为宿主的小程序使用微信登录是一件理所当然的事儿,但其实小程序并没有强制要求只能使用微信登录。
小程序在登录方式的选择上有很高的自由度:使用微信登录仅仅是其中一个选择,你完全可以使用跟其他应用(网站、App)一样的登录方式,比如手机号、邮箱、用户名密码等。

既然如此,为什么我们一定要使用微信登录呢?因为除了便利性以外,微信登录更重要的优势是整合了微信庞大的生态系统,以及对于产品策略的加持。

小程序使用微信登录的优势

对于很多公司来说,微信小程序仅仅是其产品矩阵中的一个应用端(对于微信来说 小程序也只是一个三方应用),同时存在的还有网站、App 等应用端。
从生态系统的角度上, 相对于其他应用端,以微信为入口的小程序最大的优势是拥有微信完善的生态系统,用户使用微信登录后可以使用微信提供给小程序的各种平台级能力,比如订阅消息、微信支付等。
从用户体验的角度上, 用户能够很大程度上降低登录的复杂程度。想象一下,对比在小程序内用用户名密码登录和一键微信登录,哪种方式更容易被用户接受呢?结果不言而喻。
从产品策略的角度上, 使用微信登录小程序能够根据用户的来源,制定特殊的产品策略,比如对于小程序的用户发放专属的优惠券。

所以,你可以由此得出小程序使用微信登录的三个主要优势:

  • 融入微信生态;
  • 提高用户体验;
  • 制定产品策略。

这也说明了小程序接入微信登录的必要性,那它的登录流程是什么呢?
下面这张图清晰地描绘了微信小程序完整的登录流程、角色以及相关术语。
我们先熟悉一下这些内容,然后再结合这套流程学习 OAuth 2.0 规范。

说明

  1. 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
  2. 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 、 用户在微信开放平台帐号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台帐号) 和 会话密钥 session_key。
    之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。

注意事项

  1. 会话密钥 session_key 是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。
  2. 临时登录凭证 code 只能使用一次

整个登录流程中描述了三种角色和六个术语,了解它们的定位和作用,是理解小程序登录流程的基础。

登录流程里的三个角色

客户端在整个登录流程中主要承担两种行为:

  • 作为整个流程的发起者,获取临时登录凭证 code。
  • 作为整个流程的终结者,存储登录态令牌 token。

不过客户端的所有信息和网络请求几乎都是可以被破解或拦截的,
所以出于安全的考虑,小程序登录流程中的一些接口被限制不能在客户端中直接调用,而是需要在服务端发起,开发者服务的工作便是处理这些安全敏感的网络请求。
体现为上图中使用code 获取 openid 和 session_key的请求,这个请求使用了微信提供的 auth.code2Session 接口。

而微信接口服务的工作对于开发者来说是不透明的,你需要做的仅仅是根据接口的规范,组装网络请求发送给它,然后根据返回的接口执行分发逻辑。
微信服务器会验证网络请求的合法性,对于合法请求下发密钥 session_key 和用户 openid。

登录流程的六个术语

code
它是在客户端(即小程序)内通过 wx.login API 获取的,然后通过 HTTP 请求发送给开发者服务器。code 的作用体现在“临时”两字上,它的有效期限仅有 5 分钟,并且仅能够使用一次(即请求一次 auth.code2Session 接口)。

appid
每个微信小程序在创建之后(即在微信公众平台注册并初始化完成)便同时生成了一appid,这个 ID 标记了小程序的唯一性,等同于网站的URL(经过备案的)、App 的包名等标记应用唯一性的信息。

appsecret
它是小程序的密钥,可以在微信公众平台的后台管理系统中获取。
appsecret 是非常私密的信息,所以微信在制定小程序登录的流程时,将携带此信息的网络请求限制在只能通过开发者服务器发送给微信接口服务,这样对于客户端来说是不可见的,进而降低了被泄露的可能性。
与appid 不同的是,appsecret 可以被重置,但每次重置之后,历史的 appsecret 便会失效,所以请谨慎操作。

openid
这里你要注意,很多开发者容易走入一个误区:误将 openid 理解为用户的唯一 ID。
这句话如果放在某个小程序的特定语境下是没有问题的,但是如果放在微信生态的全局角度上是错误的。
为什么呢? ---微信对于用户 openid 的定义是:

 
微信号在某个应用程序中的唯一 ID。这里的“某个应用程序”指的是小程序、公众号、接入开放平台的应用。微信生态中目前有公众平台和开放平台两种,其中公众平台又细分为小程序和公众号,开放平台可以接入网站、移动应用等。同一个微信号在不同的应用程序中有不同的 openid。

在微信生态下另外有一个标记微信号的唯一 ID:UnionId。这个 ID 跟应用程序无关。所以,可以简单地理解为 UnionId 与 appid 综合加密后的结果,见下图:

UnionId 通常用来关联在不同应用程序中各个 openid ,比如同一个微信号在小程序和公众号内需要配置同样的权限,仅通过 openid 无法实现,便需要获取此微信号的 UnionId。
虽然获取 UnionId 的流程并不在这节课的讨论范围之内,但我相信你在后续工作中一定会遇到处理 UnionId 和 openid 的场景,所以先了解一下没啥坏处。

session_key
session_key 是对用户数据进行加密签名的密钥,微信服务器使用它将用户的数据进行加密和解密。
你可以简单地将 session_key 理解为获取用户数据的“绿卡”,登录之后所有涉及访问微信服务器的请求一般都需要带上它,微信服务器会校验 session_key 的合法性。

其实到这一步(即拿到了 openid 和 session_key)已经完成了小程序的登录流程,但对于一个应用程序来说,用户进行登录操作应该是“一劳永逸”的,即登录过一次之后在一定时间之内的后续操作都不需要再次登录,用技术语言描述就是应该保存用户的登录态。这个时候就需要用到接下来的一个术语:token。

token
登录态是个逻辑词汇,token 可以理解为登录态的具象化、数据化。
在小程序的登录流程图中,你可以看出,token是由开发者服务器创建的一个字符串,而且需要跟 openid 和 session_key 相关联(其实这里并不是强制关联 openid,因为 openid 并不算是私密信息,可以放心地下发到客户端(即小程序)。但是 session_key 是非常私密的信息,一旦泄露有很大的安全隐患,所以强烈建议不要把它下发到客户端)。

在获取到 openid 和 session_key 之后,开发者服务器创建一个 token,然后与 openid 和session_key 进行关联,具体的方法根据服务器编程语言的不同有多种实现方案。
咱们以JavaScript 语言作为示例,可以创建一个对象,对象的 key 是 token 的值,value 是一个包含 openid 和 session_key 的对象,如下:

 
{
    "token_1": {
        "openid": "获取到的openid 1",
        "session_key": "获取到的session_key 1"
    },
    "token_2": {
        "openid": "获取到的openid 2",
        "session_key": "获取到的session_key 2"
    },
}

关联完成之后开发者服务器将 token下发到客户端,客户端保存在本地,后续的所有请求均需要携带此 token,携带的方法并没有既定的规范,可以通过 URL Query、HTTP Body、Header 等,但通常建议通过 Header 传递,这样相对来说更安全一些。

后续

讲到这儿,小程序接入微信登录的全部流程便讲解完成了,根据上面的内容我相信你能够搭建一套小程序登录流程。但是这就满足了吗?

我在最初搭建小程序登录流程时,也是先完成了这些内容的学习,但在完成了登录需求之后却并没有满足于仅仅知晓怎么搭建和使用,而是迫切地想进一步了解每个术语存在的意义,以及为什么登录流程被设计成这套形态。换句话说就是“知其然更知其所以然”。

我相信你一定也想更进一步丰富自己的知识储备,如果被我说中了,那么接下来我们就一起来学习小程序登录流程背后的 OAuth 2.0 规范吧。

OAuth 2.0 规范:知其然更知其所以然

OAuth 2.0 规范中的角色划分

咱们先思考一个问题:小程序登录之后如果需要访问用户的数据(比如昵称、地域、性别等)需要得到谁的授权?是微信?还是用户?
答案是用户。用户的数据虽然存放在微信的服务器之上,但是这些数据的所有权属于用户自己,而不是微信。这里其实引出了 OAuth 2.0 规范中的两个基本概念。

  • Resource Owner:资源所有者,即用户。
  • Resource Server:资源服务器,即微信。

而小程序在获取用户数据中的角色是作为微信平台的第三方应用程序,在 OAuth 2.0 规范中的术语为 Third-party application。

除了以上三种角色之外,OAuth 2.0规范中还有另外三种角色:

  • 小程序依托于微信提供的底层技术平台(即 01 讲中的双线程模型),微信为小程序提供了与用户(即Resource Owner)沟通的工具,它在 OAuth 2.0 规范中的角色被称为 User Agent(用户代理)。
  • 微信服务器不仅仅作为 Resource Server 保存用户数据,同时在登录授权过程中又提供了HTTP服务以及授权认证功能,这两个功能的角色在 OAuth 2.0 规范中分别被称为 HTTP Service(HTTP服务提供商)和Authorization server(认证服务器)。

以上便是 OAuth 2.0 规范中的所有角色,为了加强了解,我们再梳理一遍:

  • Resource Owner(资源所有者):在小程序场景下代表小程序的用户。
  • Resource Server(资源服务器,即存放用户数据、资源的服务器):在小程序场景下这个角色由微信服务器承担。
  • Third-party application(第三方应用程序/又称客户端):在小程序场景下代表小程序。
  • User Agent(用户代理):在小程序场景下代表微信。
  • Authorization server(认证服务器):在小程序场景下,这个角色由微信服务器承担。
  • HTTP Service(HTTP 服务提供商):在小程序场景下,这个角色由微信服务器承担。

学到这儿,你有没有疑惑为什么 OAuth 2.0 规范中的角色与小程序登录流程中角色不一样?
其实,小程序登录流程中的三个角色是按照实体划分的,而 OAuth 2.0 规范的角色是按照功能划分的,同一个实体可以担任一种或多种功能。
在小程序登录流程中的 3 个实体角色中,微信服务器同时担任 Resource Server、Authorization server 和HTTP Service 的功能;开发者服务器比较特殊,它即担任 HTTP Service 的功能,同时在认证流程中由于需要转发和关联 token,所以也充当了客户端的一部分功能。
而OAuth 2.0 规范如此分配角色,是为了规范一套严谨的授权流程。那么它到底解决了什么问题呢?

OAuth 2.0 规范要解决什么问题

先卖个关子,想一下这样的场景:
比如你向邻居借了衣架忘了还,某天邻居着急使用所才打电话向你要回,不巧的是你正在外地出差家里没人。
但好在你家的门锁是智能门锁,你可以将密码告诉邻居让他自己去你家里取。
但是你本着“防人之心不可无”的心理,担心邻居是否会趁机记下甚至修改你家的门锁密码。
左右为难的时候,你突然想起来你家的智能门锁可以创建临时密码,这种临时密码只能在 10 分钟之内有效,而且没有修改原本密码的权限。
所以,最终你在手机上创建了一个临时智能门锁的密码发给你的邻居。

OAuth 2.0 规范要解决的问题与上面提到的这个现实案例非常相似,简单概括就是:OAuth 2.0是一个授权机制,资源所有者告诉认证服务器,临时授予某个第三方应用访问资源服务器获取资源的权限,认证服务器给第三方应用颁发一个临时令牌,拥有这个令牌便可以获取资源数据,一旦令牌过期或失效便收回权限。

OAuth 2.0 规范中的令牌与小程序登录场景下的 token 作用是一致的,只不过 OAuth 规范只定义了令牌的作用,并没有限制它的具体使用方法,微信把 token 与 session_key 相关联,开发者服务器通过 token 取到 session_key 进而解密用户资源数据,这种使用方法是在遵循 OAuth 规范前提下的一种具体实践。

总结

我并不仅仅是告诉你如何搭建和使用微信小程序的登录流程,而是想通过这个流程引导你去学习它背后的原理知识。
小程序登录流程只是在小程序这一单一场景下的具体实践,而它背后的 OAuth 2.0 规范是在互联网业内通用的标准,以后不论是你想要接入其他第三方认证还是开发自己的认证系统,都需要遵守 OAuth2.0 规范才能够做到标准化、产品化。
通过这篇文章我希望你能够有以下收获:

  • 理解并学会搭建小程序的登录体系;
  • 熟悉 OAuth 2.0 规范,并了解授权认证的基本流程和相关术语
posted @ 2023-08-28 10:57  lclc  阅读(192)  评论(0编辑  收藏  举报