前端登录方式

JavaScrip高级教程 · 220 字

https://tech.xiaomi.com/#/pc/article-detail?id=33586

SSO

单点登录就是在多个系统中,用户只需登录一次,就可以完成其它各个系统的登录授权,而不需要在每个系统单独做一次登录验证。

同域名下Cookie实现

对于不同内部系统都在同一个一级域名下的情况,我们可以把cookie塞到一级域名下,这样二级域名对应的系统在被访问时,浏览器会自动附加上这个cookie。同时,服务端实现三个系统的session共享,即可解决同域名下的单点登录问题。

graph LR
  A[abc.com<br/>cookie] --> B[sso.abc.com]
  A --> C[app1.abc.com]
  A --> D[app2.abc.com]
  B --> E[共享服务端Session]
  C --> E
  D --> E

跨域名系统CAS实现

对于不同域下的内部系统,存在跨域问题,受浏览器同源策略的限制,系统之间的cookie不能共享,这时我们可以设置一个独立的SSO服务器,通过颁发票证的方式实现校验。其中的一种方案是CAS(中心授权服务)

  1. TGC(Ticket Granting Cookie)
    TGC 是CAS服务端根据TGT生成的每个用户的cookie,用于在客户端中标识用户的 CAS 会话。
  2. TGT(Ticket Granting Ticket)
    TGT是一个由 CAS 服务器颁发的票据,用于表示用户在 CAS 中的登录状态,也是用于验证用户登录成功的唯一方式。TGT中包含了有关用户身份的信息,如用户名、权限等。
    一般来说,TGT对象会被存放在CAS服务端的缓存中,而TGT的id会被存放到客户端的cookie中。CAS服务端可以通过TGC的值(即TGT的ID)在缓存中查找到对应的TGT对象。
    cookie中TGC和TGT的id之间就是name-value的关系,如下图所示
    前端登录方式
  3. ST(Service Ticket)
    ST 是由 CAS 服务器颁发的一次性票据,用于单次登录到服务提供方。当用户通过 CAS 客户端向服务提供方进行身份验证时,CAS 客户端会向 CAS 服务器发送 TGT,并请求一个 ST。CAS 服务器会验证 TGT 的有效性,并为用户颁发一个 ST,然后将其返回给 CAS 客户端。CAS 客户端将 ST 传递给服务提供方,服务提供方使用 ST 来验证用户的身份。其本质就是用户访问具体服务时所需的票据

第一次登陆流程

前端登录方式1
这里的session和token保存的是用户在 a 服务器的登录状态

第二次访问应用(token过期)

WebA Server认为用户登陆失效了,仍然重定向到cas/login ,此时浏览器会带上之前的TGC和TGT请求CAS的login接口,之后的步骤与第一次相同。这也是导致隔一段时间会有一个CAS跳转的原因。

访问另一个应用B

前端登录方式2

JWT(JSON Web Token)

背景

前端登录方式3
上图是最原始的登陆流程,不难看出,该流程中服务器的任务比较重,一方面要承担校验工作,另一方面所有的用户信息都存储在服务器端。同时,对于跨域问题和分布式场景,该方式也力不从心。

原理

服务端完成用户的登录认证之后,生成一个JSON对象,这个对象中存有加密后的用户信息,之后每次向服务端发送请求时都会带上这个对象用于服务端认证用户身份。JWT的整体流程如下:
前端登录方式4

JWT结构

JWT包含三部分:Header(头部)、Payload(负载)、Singature(签名)

  1. Header
    JSON对象,描述JWT的元数据,最后使用Base64URL转成字符串
    {
        "alg": "HS256", // 签名算法,默认是 HMAC SHA256
        "typ": "JWT" // token的类型,jwt固定写为“JWT”
    }
    
  2. Payload
    也是JSON对象,存放实际要传输的数据,也是使用Base64URL算法转成字符串,提供了7个默认字段,也可以定义私有字段。
    • iss (issuer):签发人
    • exp (expiration time):过期时间
    • sub (subject):主题
    • aud (audience):受众
    • nbf (Not Before):生效时间
    • iat (Issued At):签发时间
    • jti (JWT ID):编号
  3. Singature
    是对Header和Payload的签名,根据Header中指定的加密算法,将Header和Payload的转换结果进行加密,得到最终的签名结果,具体算法可以概括为:
    // secretKey是用于加密的密钥,只有持有密钥的一方才能验证签名
    HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload), secretKey)
    

JWT的最终结果是三者用.分隔组成的字符串

JWT特点

  1. 优点:
    JWT 不仅可以用于认证,也可以用于交换信息。例如,我们可以把用户的偏好设置(如界面语言、字体大小、主题等)放到JWT中传给服务器,服务器根据JWT中的偏好设置来定制响应内容。

  2. 缺点:
    由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务端增加额外的处理逻辑(比如增加IP地址限制、黑白名单策略)。因此,一般情况下JWT 的有效期应该设置得比较短,同时颁发一个刷新令牌(refresh token)给客户端用于获取新的访问令牌。这样,如果你需要废止用户的访问权限,你可以使刷新令牌失效,这样用户就无法再获取新的访问令牌

OAuth2

常见的微信、QQ、Google账号等第三方账号授权登陆的形式。
前端登录方式5

为什么不能直接颁发令牌?

出于安全性的考虑。如果认证服务器直接给客户端颁发令牌,那么令牌可能会在传输过程中被恶意第三方插件、脚本等截获,用信息也就会被泄露。通过使用授权码作为中间步骤,客户端不会直接处理令牌,也就降低了令牌泄露的风险。并且在授权码流程中,客户端在获取到授权码后,还需要将其与客户端ID和客户端密钥一起发送给授权服务器,才能拿到令牌。