账户体系(SSO, JWT与OAuth)

SSO

  • 单点登录(SSO: Single Sign-On)
    • 一套公用的用户体系,用户只要登陆之后,就能够访问所有的系统
      • 比如人力资源,代码管理等
  • 也用于解决跨域问题

JWT

  • JWT就像一个临时的用户凭证,代替了用户名和密码组合

  • JWT 的目的不是为了隐藏或者保密数据,而是为了确保数据确实来自被授权的人创建的(不被篡改)

  • 优点

    • 为了确认它是否有效,我们只需要看JWT本身的内容,而不需要借助于第三方服务或者在多个请求之间将其保存在内存中(session)
      • 因为它本身携带了信息验证码MAC(Message Authentication Code)
  • 缺点

    • 服务后台无法拒绝携带JWT的请求(如踢除用户)
    • 服务器端没法统计多少个人登录了,一个人登录了多少次,登陆了什么设备
    • 无法很好的控制payload的数据量
      • 应该只把认证的相关信息放到payload里。但实际上,开发人员往往会误用,把几乎所有和user相关的数据都放到payload里
      • 会极大的损耗带宽和IO性能,因为每次请求都必须把全量的JWT都带着
  • JWT一般用于身份验证,不用于储存会话状态(代替cookie)

  • 它是 JSON 结构的 token,由三部分组成:header,payload,signature

    • 格式Base64(Header) + "." + Base64(Payload) + "." + $Signature
    • header
      • JSON对象,用于描述元信息,例如产生 signature 的算法
    • payload
      • 用于携带希望向服务端传递的信息
      • 由于payload不加密,建议只在其中保存非敏感的用于身份验证的数据
    • signature 用于校验合法性
      • 利用认证服务器的**进行签名
      • 格式HS256(Base64(Header) + "." + Base64(Payload), secretKey)
        • 也不一定要使用HS256加密
  • 客户端发送方式

    • 你可以把JWT放在 Cookie 里面自动发送,但是这样不能跨域
    • 更好的做法是放在 HTTP 请求的头信息Authorization字段里面
      • Authorization: Bearer<token>
    • 或者放在 POST 请求的数据体里面
  • 认证流程

    • 用户向认证服务器提交用户名和密码
      • 认证服务器也可以和应用服务器部署在一起,但往往是独立的居多
    • 认证服务器校验用户名和密码组合,然后创建一个JWT token,发送给客户端
      • token的Payload里面包含用户的身份信息,以及过期时间戳
      • 使用私钥对Header和Payload进行签名
      • 只有认证服务器拥有私钥
    • 客户端之后的每个HTTP请求中附带着发送给应用服务器
    • 应用服务器使用公钥检查JWT签名,确认Payload确实是由**拥有者签过名的
  • 为什么不直接对payload进行加密

    • RSA加密过程比较慢,对于数据比较大的Payload来说,可能会是个问题
      账户体系(SSO, JWT与OAuth)
  • 参考:

OAuth

  • OAuth是让第三方应用不需要用户名密码读取用户数据的一个认证过程
    • 但通过oauth方式授权,第三方应用可以凭借他手中的授权"凭证" (access token) 做一些他想做的事情,比如直接帮你关注某个微博账号
  • 第三方登录授权流程(以GitHub登录A网站为例)
    • 登陆前
    • 登陆时
      • GitHub要求用户登录并询问是否允许授权A网站
      • 用户同意,GitHub 就会重定向回 A 网站注册的跳转网址,同时发回一个授权码(code)
      • A 网站使用授权码,向 GitHub 请求令牌
        • 需要提供client_idclient_secretcode
        • 令牌有过期时间和权限范围
      • A 网站使用Github返回的令牌(accessToken),向 GitHub 请求用户数据
    • 为什么第一次要返回code,而不是token?
      • 原因1:
        • A网址第一次请求GitHub时不会带上 client_secret,因为无法证明该网站就是GitHub
        • 而GitHub为了验证A网址合法性,需要在获得client_secret后才发放token
      • 原因2:
        • 授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成(HTTPS)
          • 这样的前后端分离,可以避免令牌泄漏
        • 如果是纯前端应用,则直接范围token
          • 这样很不安全的,因此只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短
    • 为什么要返回令牌而不是直接返回用户数据?
      • 因为A网址可能一段时间后又需要请求该数据或者需要请求其他数据,此时可以复用令牌,而不用再次鉴权

账户体系(SSO, JWT与OAuth)