常见登陆鉴权方案

编者注:今天咱们分享的是卢士杰同窗整理的网站经常使用鉴权方案的实现原理与实现以及他们的适用场景,帮助你们在业务中作合适的选择。html

背景

提及鉴权你们应该都很熟悉,不过做为前端开发来说,鉴权的流程大头都在后端小哥那边,本文的目的就是为了让你们了解一下常见的鉴权的方式和原理。前端

认知:HTTP 是一个无状态协议,因此客户端每次发出请求时,下一次请求没法得知上一次请求所包含的状态数据。mysql

1、HTTP Auth Authentication

简介

HTTP 提供一个用于权限控制和认证的通用框架。最经常使用的HTTP认证方案是HTTP Basic Authenticationgit

鉴权流程

加解密过程

// Authorization 加密过程
let email = "postmail@test.com"
let password = "12345678"
let auth = `${email}:${password}`
const buf = Buffer.from(auth, 'ascii');
console.info(buf.toString('base64')); // cG9zdG1haWxAdGVzdC5jb206MTIzNDU2Nzg=

// Authorization 解密过程
const buf = Buffer.from(authorization.split(' ')[1] || ''),  'base64');
const user = buf.toString('ascii').split(':');

其余 HTTP 认证

通用 HTTP 身份验证框架有多个验证方案使用。不一样的验证方案会在安全强度上有所不一样。github

IANA 维护了一系列的验证方案,除此以外还有其余类型的验证方案由虚拟主机服务提供,例如 Amazon AWS ,常见的验证方案包括:redis

  • Basic (查看 RFC 7617, Base64 编码凭证. 详情请参阅下文.),
  • Bearer (查看 RFC 6750, bearer 令牌经过OAuth 2.0保护资源),
  • Digest (查看 RFC 7616, 只有 md5 散列 在Firefox中支持, 查看 bug 472823 用于SHA加密支持),
  • HOBA (查看 RFC 7486 (草案), HTTP Origin-Bound 认证, 基于数字签名),
  • Mutual (查看 draft-ietf-httpauth-mutual),
  • AWS4-HMAC-SHA256 (查看 AWS docs)

2、Cookie + Session

注册流程

思考:为何要在密码里加点“盐”?sql

鉴权流程

Session 存储

最经常使用的 Session 存储方式是 KV 存储,如Redis,在分布式、API 支持、性能方面都是比较好的,除此以外还有 mysql、file 存储。后端

若是服务是分布式的,使用 file 存储,多个服务间存在同步 session 的问题;高并发状况下错误读写锁的控制。安全

Session Refresh

咱们上面提到的流程中,缺乏 Session 的刷新的环节,咱们不能在用户登陆以后通过一个 expires 时间就把用户踢出去,若是在 Session 有效期间用户一直在操做,这时候 expires 时间就应该刷新。服务器

以 Koa 为例,刷新 Session 的机制也比较简单:
开发一个 middleware(默认状况下全部请求都会通过该 middleware),若是校验 Session 有效,就更新 Session 的 expires: 当前时间+过时时间。

优化:

  1. 频繁更新 session 会影响性能,能够在 session 快过时的时候再更新过时时间。
  2. 若是某个用户一直在操做,同一个 sessionID 可能会长期有效,若是相关 cookie 泄露,可能致使比较大的风险,能够在生成 sessionID 的同时生成一个 refreshID,在 sessionID 过时以后使用 refreshID 请求服务端生成新的 sessionID(这个方案须要前端判断 sessionID 失效,并携带 refreshID 发请求)。

单设备登陆

有些状况下,只容许一个账号在一个端下登陆,若是换了一个端,须要把以前登陆的端踢下线(默认状况下,同一个账号能够在不一样的端下同时登陆的)。

这时候能够借助一个服务保存用户惟一标识和 sessionId 值的对应关系,若是同一个用户,但 sessionId 不同,则不容许登陆或者把以前的踢下线(删除旧 session )。

3、JWT

简介

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于做为JSON对象在各方之间安全地传输信息。该信息能够被验证和信任,由于它是数字签名的。

JWT 组成

JWT 由三部分组成,分别是 header(头部),payload(载荷),signature(签证) 这三部分以小数点链接起来。

例如使用名为 jwt-token 的cookie来存储 JWT 例如:

jwt-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibHVzaGlqaWUiLCJpYXQiOjE1MzI1OTUyNTUsImV4cCI6MTUzMjU5NTI3MH0.WZ9_poToN9llFFUfkswcpTljRDjF4JfZcmqYS0JcKO8;

使用.分割值能够获得三部分组成元素,按照顺序分别为:

  • header

    • 值:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    • Base64 解码: {"alg": "HS256", "type": "JWT"}
  • payload

    • 值:eyJuYW1lIjoibHVzaGlqaWUiLCJpYXQiOjE1MzI1OTUyNTUsImV4cCI6MTUzMjU5NTI3MH0
    • Base64 解码:

      {
        "name": "lushijie", 
        "iat": 1532595255, // 发布时间
        "exp": 1532595270 // 过时时间
      }
  • signature

    • 值:WZ9_poToN9llFFUfkswcpTljRDjF4JfZcmqYS0JcKO8
    • 解码:

      const headerEncode = base64Encode(header);
      const payloadEncode = base64Encode(payload);
      let signature = HMACSHA256(headerEncode + '.' + payloadEncode, '密钥');

鉴权流程

Token 校验

对于验证一个 JWT 是否有效也是比较简单的,服务端根据前面介绍的计算方法计算出 signature,和要校验的JWT中的 signature 部分进行对比就能够了,若是 signature 部分相等则是一个有效的 JWT。

Token Refresh

为了减小 JWT Token 泄露风险,通常有效期会设置的比较短。 这样就会存在 JWT Token 过时的状况,咱们不可能让用户频繁去登陆获取新的 JWT Token。

解决方案:

能够同时生成 JWT Token 与 Refresh Token,其中 Refresh Roken 的有效时间长于 JWT Token,这样当 JWT Token 过时以后,使用 Refresh Token 获取新的 JWT Token 与 Refresh Token,其中 Refresh Token 只能使用一次。

4、OAuth

简介

有时候,咱们登陆某个网站,但咱们又不想注册该网站的帐号,这时咱们可使用第三方帐号登陆,好比 github、微博、微信、QQ等。

开放受权(OAuth)是一个开放标准,容许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。

OAuth容许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每个令牌受权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户能够受权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非全部内容。

OAuth是OpenID的一个补充,可是彻底不一样的服务。

—— 摘自 维基百科

受权流程

名词解释:

  • Third-party application:第三方应用程序又称"客户端"(client),好比打开知乎,使用第三方登陆,选择 Github 登陆,这时候知乎就是客户端。
  • Resource Owner:资源全部者,本文中又称"用户"(user),即登陆用户。
  • Authorization server:认证服务器,即 Github 专门用来处理认证的服务器。
  • Resource server:资源服务器,即 Github 存放用户生成的资源的服务器。它与认证服务器,能够是同一台服务器,也能够是不一样的服务器。

  • A. A网站让用户跳转到 GitHub,请求受权码;GitHub 要求用户登陆,而后询问“知乎网站要求得到 xx 权限,你是否赞成?”;
  • B. 用户赞成,GitHub 就会重定向回 A 网站,同时发回一个受权码;
  • C. A 网站使用受权码,向 GitHub 请求令牌;
  • D. GitHub 返回令牌;
  • E. A 网站使用令牌,向 GitHub 请求用户数据;

其余受权模式

受权码模式(authorization code)是功能最完整、流程最严密的受权模式。除了咱们上面所说的受权码模式,其实还有其余受权模式:

  1. 简化模式(Implicit grant type)
    有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。RFC 6749 就规定了第二种方式,容许直接向前端颁发令牌。这种方式没有受权码这个中间步骤
  2. 密码模式(Resource Owner Password Credentials Grant)
    若是你高度信任某个应用,RFC 6749 也容许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌
  3. 客户端模式(Client Credentials Grant)
    适用于没有前端的命令行应用,即在命令行下请求令牌

关于这些模式详细请见:OAuth2.0 的四种方式

单点登陆

单点登陆(Single Sign On, SSO),即:单一标记(单点)登陆。例如:QQ,我在QQ空间登陆一次,我能够去访问QQ产品的其余服务:QQ邮箱、腾讯新闻等,都能保证你的帐户保持登陆状态。

延伸阅读:

5、总结对比

没有最好,只有最合适!!!

  • HTTP Auth Authentication:

    • 梳理总结:
      通用 HTTP 身份验证框架有多个验证方案使用。不一样的验证方案会在安全强度上有所不一样。HTTP Auth Authentication 是最经常使用的 HTTP认证方案,为了减小泄露风险通常要求 HTTPS 协议。
    • 适用场景:
      通常多被用在内部安全性要求不高的的系统上,如路由器网页管理接口
    • 问题:

      1. 请求上携带验证信息,容易被嗅探到
      2. 没法注销
  • Cookie + Session:

    • 梳理总结:

      • 服务端存储 session ,客户端存储 cookie,其中 cookie 保存的为 sessionID
      • 能够灵活 revoke 权限,更新信息后能够方便的同步 session 中相应内容
      • 分布式 session 通常使用 redis(或其余KV) 存储
    • 使用场景:
      适合传统系统独立鉴权
  • JWT:

    • 梳理总结:

      • 服务器再也不须要存储 session,服务器认证鉴权业务能够方便扩展
      • JWT 并不依赖 cookie,也可使用 header 传递
      • 为减小盗用,要使用 HTTPS 协议传输
    • 适用场景:

      • 适合作简单的 RESTful API 认证
      • 适合一次性验证,例如注册激活连接
    • 问题:

      1. 使用过程当中没法废弃某个 token,有效期内 token 一直有效
      2. payload 信息更新时,已下发的 token 没法同步
  • OAuth:

    • 梳理总结:

      • OAuth是一个开放标准,容许用户受权第三方应用访问他们存储在另外的服务提供者上的信息,而不须要将用户名和密码提供给第三方移动应用或分享他们数据的全部内容。
      • GitHub OAuth 文档 Identifying and authorizing users for GitHub Apps
    • 适用场景:
      OAuth 分为下面四种模式

      1. 简化模式,不安全,适用于纯静态页面应用
      2. 受权码模式,功能最完整、流程最严密的受权模式,一般使用在公网的开放平台中
      3. 密码模式,通常在内部系统中使用,调用者是以用户为单位。
      4. 客户端模式,通常在内部系统之间的 API 调用。两个平台之间调用,以平台为单位。
相关文章
相关标签/搜索