单Web应用系统登录设计

基于session会话的登录认证机制

该机制的核心在于服务器session和客户端sessionId的交互。用户登录完成后,服务器会构建用户会话session,会话内包含了用户标志及登录状态,并向浏览器返回sessoinId。之后用户在做其他接口请求时,将sessionId携带上。服务器检索到会话session并进行登录鉴权判断。

整个机制是十分简单明了的,但在设计细节上,还是由很多发挥的空间。我们先看一看session会话登录认证机制的基本流程

3种web会话管理的方式——服务器session的交互模式.png

认证过程大致如下:

  1. 用户输入用户名、密码或者用短信验证码方式登录系统;
  2. 服务端验证后,创建一个 Session 信息,并且将 SessionID 存到 cookie,发送回浏览器;
  3. 下次客户端再发起请求,自动带上 cookie 信息,服务端通过 cookie 获取 Session 信息进行校验;

问题点:

  1. 会话信息直接存储在什么地方? 对于用户量少的非分布式web系统,可以直接使用代码框架的session能力。反之,则需要一套缓存服务(redis)在多台web服务器之间共享session会话。

  2. cookie 存在 CSRF(跨站请求伪造)的风险。sessionId的cookie属性设置为httpOnly和secure,保证cookie值不能被前端js代码读取到;通过校验reffer header是否合法,防止非自有web系统发起的请求;通过使用https协议,防止黑客冒充合法的web系统。

  3. 用户会话保持和失效——用户登出则服务器session清除。用户长时间不操作用户状态失效(设定缓存时间),用户持续发起请求则用户状态保持登录(会话快过期时刷新失效时间),浏览器关闭重开是否保持会话可通过cookie属性设置。

  4. sessionId理论上还能放置在什么地方?除了放置在cookie里,理论上还可以放置在header中,body中,url路径中。放header中是可行的,但一般是在app应用里。对于web应用,还需把sessionId先存储在localstorage,那样才能在新开浏览器tab时读取重新放置到header中。放在body里理论上可以,但对于服务端的鉴权会更麻烦。放在url里则是不安全的,可通过csrf被黑客截取到。

基于token鉴权的登录认证机制

token鉴权是一种直接把用户的登录凭证直接存到客户端的方案。在用户登录验证成功之后,将登录凭证做数字签名和加密之为token返回给客户端。用户在做其他接口请求时,将token携带上。服务器将该token解密验签判断其有效性。

整个机制的关键在于token的生成和验证


3种web会话管理的方式——cookie-based的交互逻辑.png

问题:

  1. 经过签名加密后,token字符串会很长,但里面有效信息占比较小,同时也影响性能。 尽量减少token里的信息量,最简单的形式可以只包含用户id,凭证创建时间和过期时间三个值。

  2. token如何保证每次登录的安全随机? 如上,添加上时间戳可以保证每次登录的token值都不一样。

  3. 用户会话保持和失效——用户登出则清理客户端token,用户长时间不操作用户状态失效(token中含缓存时间),用户持续发起请求则用户状态保持登录(每次请求刷新token返回),浏览器关闭重开是否保持会话token保存位置决定。

  4. token放置的位置。可以放在cookie中,CSRF风险同会话管理。每次请求都可以无感刷新token。对于app客户端。放在header上,则可能存储在localstorage或sessionStorage里,其生命周期影响了会话保持。

两类登录认证机制的对比

这两种登录认证机制差异还是蛮大的。

从原理层面上看,session会话机制中,服务器为你保管了登录凭证,然后给了客户端一个信物。客户端带着信物访问,服务器能根据这个信息找到登录凭证就是有效的;token认证机制中,服务器将登录凭证打上记号锁在盒子里再给到客户端。客户端带着这个上锁的盒子访问,服务器拿出他的锁打开并检查记号,都对上了则说明登录凭证可以使用。当然,登录凭证里也有失效

从效果层面上看,session会话机制中,服务器需要自己腾出空间保存凭证和记录,而token认证机制中,服务器则只需保管好钥匙,信息本身是保存在客户端。因此,session会话需要更多存储空间;token认证机制需要额外的token解析时间,本身不存储任何用户的登录状态

但有时候,又不是那么绝对。例如token鉴权中,对于强业务的web系统,后端web服务必然也还会再关联个session会话做业务逻辑的处理;对于要求用户单端登录的情况,如果同时异地登录,旧的token要求被踢下,此时后端web服务就得存储用户token及ip或设备等信息。具体的设计原则,还是得看系统的业务属性。毕竟,一个系统,可不会仅包含用户登录鉴权。

附:初始登录鉴权

自有账号体系登录

三方账号 Oauth2.0 登录流程

流程示意图:

[图片上传失败...(image-a55a38-1609677363093)]

  1. 用户选择华为帐号登录,开发者应用发起授权码Code请求。
  2. 华为帐号服务器呈现授权页面给用户,用户确认授权。
  3. 华为帐号服务器通过开发者应用配置的回调地址,返回授权码Code。(
  4. 开发者应用发起Code换Token请求。
  5. 华为帐号服务器返回凭证(Access Token)、用户信息(ID Token)。
  6. 之后用上一步获取的 access_token 去请求华为账号服务器获取用户的基本信息,例如头像、昵称等;
  7. 保存到用户凭证中,完成登录。

自有系统 SSO单点登录

流程示意图:

单web应用系统登录设计——子系统SSO登录流程.png
  1. 用户向后台业务系统发起请求时,先验证局部登录会话是否创建。如果未创建,则先跳转到SSO单点登录系统进行登录操作.
  2. SSO认证中心引导用户登录,完成登录验证
  3. 验证OK,则生成ticket.并将User对象转化为JSON数据,创建全局会话。(这里基于cookie-session的机制)
  4. 携带ticket跳转回业务系统的前台页面 (当业务系统与SSO认证中心同域的情况下,ticket可直接放在域名cookie下)
  5. 用户重新在浏览器页面发起了操作
  6. 业务系统后台向SSO认证中心验证ticket合法性,以获取用户登录凭证。并在自己的服务域名下创建局部会话。

以上两个流程实际上大同小异,都遵循外部鉴权系统的两个核心步骤————鉴权认证中心(外部账号系统、自有SSO认证中心)在登录完成后颁发令牌,业务系统拿着该令牌向鉴权认证中心请求验证。 前一步可以通过cookie或url参数的性质通过前端传到业务系统,该令牌被泄露了也无关紧要;第二步则由后台服务向鉴权中心发起认证,这里则需要服务之间的互信。oauth机制中,可以通过appid和secret来保证互信。SSO认证中心则可以通过秘钥管理的方式来保证互信。

你可能感兴趣的:(单Web应用系统登录设计)