Web、APP和小程序账户登录机制差异

摘要
同样是账户登录功能,在面对不同渠道和场景时,需要进行一定的优化适配。本文从最早期的Web登录机制讲起,谈谈同样的登录功能在APP以及小程序上的变化。

为什么要登录
登录的本质是为了区分不同的用户。

在 Web 1.0 时代,用户往往只需要上网检索一些已发布的信息,例如看看新闻之类的,网站发布方无需针对不同的用户提供不同的内容,因此也无需知道是谁在访问内容。

进入Web 2.0 时代,一些博客平台和论坛的兴起,用户开始自发创造内容,因此产生了新的需求——用户可管理自己创建的内容,那么问题就来了,网站需要鉴别哪些内容是当前访问的用户创建的,哪些不是当前用户创建的。

解决方案也很简单,增加了一个用户注册和登录功能,用户创建账号并登录,使用这个账户创建内容,后续内容创建完成后,记录创建者为当前用户。下次无论是谁验证了账号密码登录这个账号,那么谁就是这个内容的创建者。

HTTP是无状态的
上述的这个方案,在逻辑上理解是可行的,但在实际运行时,还会遇到新的问题。第一个问题就是:由于HTTP是无状态的,如果要使用账号密码验证身份,每一次操作都需要再重复输入账号密码。

缺少HTTP背景知识的读者可能很难理解这里的“无状态”的含义。其实无状态的含义是,无法实现状态管理,这是从HTTP协议本身就定了的,对应到本例,也就是已经进行身份认证的的用户的状态无法通过HTTP协议层面保存下来。

通俗地讲,对于服务器端来讲,每一次接收的HTTP请求都是全新的,仅通过HTTP协议本身,服务器端无法知道以下内容:

是谁发起的请求。
发起请求的请求方之前是否发起过请求。
回到上面的这个例子,A用户发布内容的时候,输入的账号密码验证身份,过了一会又要发新帖子,如果本次不输入账户密码,那么服务器就不知道发布人的身份,即便他刚刚才验证过。

我们讲一个生活中的例子来更形象地了解什么是“无状态”。

假设有一个幼儿园,每天放学了了家长们都回来门卫处告知门卫要接哪个小孩。

首先,家长A来到窗口,喊道:“我是家长A,我来接小a。”(发起请求)

接下去门卫肯定不同意,要是来个人就把小孩接走了,别人冒充怎么办。于是门卫回答到:“你怎么证明呢?”(需要身份验证)

于是家长A拿出了户口本,门卫一看,发现确实是这样,(身份验证通过),于是从里面把小a带出来,交给了家长A。(返回响应)

以上就是一次请求的结果。接下去第2天放学,家长A又来准备接小a了。于是家长A就对门卫说:“我昨天刚来结果小a,我是他家长,你应该记得吧。”

门卫回答到:“我不记得你是谁,也不记得你有没有来过,但是如果你要接小a,那就出示证明,证明你是小a的家长。”

上面例子门卫说的“不记得”就是“无状态”,如果记得那就是“有状态”的。

家长A一想,大家都这么熟了,每次来都要验证身份,实在是太麻烦了,于是想出了一个办法,对门卫说:“虽然你没办法记住我是谁,但是你自己的东西得认吧,你写一张字条,写上这人就是家长A,然后你签名。当我拿着这个字条的时候,就用这个说明我的身份。”

门卫一想,好主意。就这么办。

保持登录状态
细心的读者应该能发现,平时自己在网上冲浪的过程中,一般只需要登录一次即可,不会每点击一次,就让自己输一遍账号和密码,这就是用到了上面说到的那个方案,只是这套方案的运转对于终端用户来说是完全无感知的,也就是采用的上述所说的这个方案。

这套方案的核心逻辑如下。

第1步:用户在客户端登录时,进行身份验证(例如输入账号密码等),将认证信息发送给服务端。

第2步:服务端接收到认证信息后,进行核对,如果身份验证通过(即账号密码正确),则给客户端发送一个凭证,同时保存对应的映射关系,即该凭证对应到哪个账户。

第3步:客户端保存由服务端下发的凭证,后续需要进行身份验证的场景,客户端发起请求时直接带上这个凭证,表明是这个用户。

第4步:服务端接收到客户端的请求,检测凭证对应的映射关系,从而知道是哪个账户要进行什么操作。

上述第2步提到的凭证,在不同的地方,有不同的名称,并没有建立统一的名称,有的地方叫“Session ID”,有的地方叫“access token”,还有地方直接叫“token”,你只要明白,这些只是叫法不同,本质上还是一回事。

上述的这4步阐述了整个功能运转的核心逻辑,我们结合使用场景继续补充分支逻辑和细节。

Web登录机制
事实上,上述的方案并不严谨,其中一个缺点是,在Web场景下,早期一台电脑可能多人共用或者存在临时在其他电脑登录情况,可能存在凭证(为方便说明,下面凭证统一称为“token”)被盗情况,或者临时在他人电脑登录导致帐号被误用情况。这就需要对token进行更高级的管理,一个策略是定义token的有效期,让token仅在一段时间内有效,超出时间后无效,减少被盗用的影响。另一个策略是本地删除token防止被盗用。

因此,在Web端,相对于上述核心逻辑的补充部分如下:

(1)服务端生成token时,除了记录对应的账户ID,还创建一个有效期,即有效截止时间,超过该时间该token定义为无效。

(2)服务端下发token时,同时下发有效期。

(3)客户端在发起请求(需要身份认证场景)时,仅在本地存有token且token在有效期内,才向服务器发起请求时携带该token,否则就要求用户进行登录。

再进一步,还存在以下场景:用户发现自己的账号泄漏密码被别人登录了,这个时候用户修改密码,要求修改密码后,所有已登录的客户端都需要重新登录,以此来保护账号。

这种情况,对于token映射表,我们再增加一个字段——token是否有效,当修改密码后,该账户对应的所有token都标记为无效。之后客户端再请求时,告知无效,需要重新登录。

需要特别说明的是,上述提到的“标记为失效”,实际上更好的策略是:直接删除该条映射记录——后续检索时,无法匹配到记录,则定义为该条为失效状态。后续描述不再对此额外说明,统一使用“标记为失效”来说明——实际采用新增一个字段记录是否有效或直接删除该条记录可根据系统架构来设计。

综上,我们给出一个完整的方案。(*仅提供文字说明,完整流程图后续补充)

(1)对于需要身份认证的接口,客户端发起请求时,判断本地Cookie是否存有token信息且token出于有效期内。若是,则直接携带该token发起请求,若为否,则跳转登录页,要求用户先进行登录。

(2)用户在客户端输入账户信息登录时,由客户端将身份认证信息(例如账户名、密码或其他方式等)发往服务端。(这里我们不讨论例如加密等的信息安全性问题。)服务端进行验证,如果验证通过,则产生一条token和账户ID的映射记录,该表包含以下字段:

token:只需不重复即可,为防止暴力枚举,尽量在12位以上
账户ID:与token绑定的账户ID
有效期:即有效期的结束时间,无需记录开始时间
是否有效:可单独使用该字段,也可采取删除整条记录来标记失效,下述描述采用当前字段进行叙述。
当然,如果验证不通过,就服务端告知客户端,要求重新输入认证信息。

(3)客户端判定本地token有效后(实际不一定有效,以服务端为准),将请求携带token发往服务端。服务端首先验证token有效性(token匹配,同时当前时间在有效期内且是否有效字段为有效)。若有效,则继续完成请求,若判定无效,则告知客户端,要求用户重新登录。

简单讲,其实在Web保持登录状态就是存了一个能够证明用户身份的凭证(token),谁拿着这个凭证,谁就能代表这个用户。其他的逻辑都是为了增加这个凭证的安全性服务的。

APP登录机制
在APP上保持登录状态的逻辑和Web基本一致。相对于Web而言,APP的特点是:设备私有,常规情况下为单人使用,较少出现设备共用情况。因此在APP端设定的token相对于Web而言,可以设立更长的有效期。

需要注意的是,对于多端登录设备而言,例如可以同时在Web和APP登录,需要使用2套token,可以在token表中新增字段“渠道”来记录token的使用场景,可以大大方便后续的管理(后面会说)。

小程序登录机制
小程序的登录机制和Web和APP相比,有很大的不同。由于小程序是运行在“微信”APP上的,微信提供了区分每个用户的方式(详见文章《从打开小程序到获取OpenID的过程中,发生了什么?》),因此在小程序中,可以认为:用户永远保持登录状态。

虽然服务端可以随时通过openID得知当前用户身份,但是这一个获取过程还是比较麻烦且耗时的,因此核心逻辑还是和Web以及APP一样,获取身份后下发token,以后请求带上token来告知身份。

小程序不同的点在于获取token的时机,在Web和APP中,很简单,服务端完成身份验证即时下发token,这个时机是用户主动发起的(主动进行登录操作),而在小程序,如果还是按照这套逻辑运行,无疑大大浪费了原生“带状态”优势,造成用户操作不便。

一般小程序获取token的时机采取以下策略:

(1)小程序端判断本地token是否有token且在有效期内,若为否,则由小程序段向服务端发起获取token请求(具体流程见文章《从打开小程序到获取OpenID的过程中,发生了什么?》),获取后本地保存;若为是,则不发起。

(2)服务端收到带有token的请求后,判断token的有效性,若有效,则进行下一步操作;若无效,则通知小程序端发起获取token请求(用户无感知,无操作)。

按照以上策略,小程序端随时可以获取有效token,而用户无需任何操作。那么如何处理多端账户呢?

很常见的一个业务场景是,某电商产品,存在Web、APP和小程序客户端,在小程序客户端,要获取用户信息,需要进行登录。实际上,更准确地讲,小程序里说“绑定账户”更准确一点。

一个通用的策略是:用户账户表包含手机号、邮箱、openID字段,在小程序登录时,该账户和微信账户建立绑定关系,即openID字段填入对应值即可。在小程序请求获取token时,服务端判断传过来的openID是否有绑定账户,若有,则新生成的token关联至该账户(账户ID),若无,处理策略根据业务场景而定。(比如有的产品仅包含小程序端,就直接建立一个新账户即可。)

这里采取这样的策略并不是强制的,只是采取这种方案能够更好的利用在微信体系内的既有优势。实际上,很多不懂这一点的开发者,直接将在微信上获取token的逻辑处理成和APP内一模一样的人也大有人在。两种方案的区别在于,前者无论用户进行什么操作(包含换手机、清缓存等,除了解绑账户),用户都无需再次输入账户密码进行登录,大大方便了用户。而后者,只要被清缓存,都需要再次输入账户密码进行登录重新获取token。

主要业务场景处理
我们知道,账户级别的操作,常见的有:

注册
登录
解绑手机号
解绑邮箱
更改密码
解绑微信
只要按照以上这套策略设计流程,以上各种操作的逻辑处理将非常简单:

解绑手机号
账户表的“手机号”字段清空,重新绑定则存入新手机号。解绑和绑定邮箱逻辑一样。

引起的附加变化一般有,如果该账户当前在Web上登录了,按照大多数的业务要求,一般会要求该账户无法继续操作,需要重新登录才能操作。对应到token逻辑,只需要检索到手机渠道且对应该账户的token,标记为失效即可。

解绑微信
从表面上看起来,解绑微信和手机号很不一样,但本质上还是一回事(虽然大多数应用在小程序内将“绑定”显示操作名称为“登录”),绑定微信则openID字段填入对应值,解绑则直接清空即可。引起的附加变化和解绑手机号逻辑一致。

更改密码
一般更改密码后,会要求用户重新登录才能使用,所用的逻辑也和上面一致,在服务端token表中将需要重新登录的客户端对应token标记为“失效”即可。(另一个常见操作是将某客户端已登录的踢下线,逻辑也是一样)。

总结
如果理解了背后的原因,其实设计一套以上这样的方案并不难,关键是我们要明白为什么要这么做。

要深刻明白的一点是,代码逻辑是支撑业务的,业务需要是要做某件事情的起点。

需要登录的原因是,产品有个性化内容,需要使用识别不同的用户,登录是解决这个问题的一种方式。

需要使用token的原因是,为了保持登录状态。

保持登录状态的原因是,如果登录状态不保持,用户每一个操作都需要重新进行一次身份验证,对用户来说操作太麻烦,会造成用户流失。

微信小程序token机制不同的原因是,在微信内可以时刻获取用户身份,不需要用户额外手动登录,目的也是为了方便用户操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值