前端鉴权方案

241 阅读7分钟

概念介绍

认证(Authentication) :验证当前用户的身份,证明“你是你自己”。比如用户密码登录、邮箱发送登录链接、手机号接收验证码等,只要你能收到邮件或验证码就默认你是主人。

授权(Authorization) :用户授予第三方应用访问该用户某些资源的权限就是授权。比如安装APP时,会询问是否允许授予访问地理位置、通讯录等权限,常见的授权方式有 cookie、session、token 和 jwt

实现认证和授权的前提是需要一个 证书(Credentials) 来标记访问者的身份。

一、Cookie

Cookie与前端安全

二、Session

  • session 存储在服务端session是另一种记录服务器和客户端会话状态的机制。
  • session 是基于cookie实现的,sessionID会被存储到客户端的cookie

1. 认证过程

image.png

  1. 用户第一次请求服务器时,服务器会根据提交的信息创建对应的 Session,并将SessionID放到响应中返回(此Session的唯一标识信息,放在响应头中)。

  2. 客户端接收到sessionID后,会将它存入 cookie中(Set-Cookie)

  3. (1) 当用户再次访问服务器时,请求会携带该域名下对应的cookie。(2) 然后服务端会从 cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息。如果能找到就通过验证、执行后续的操作,否则就中断。

2. cookie 和 session区别

  1. 存储位置:客户端;服务端。
  2. 安全性(由存储位置导致的):cookie 可以通过客户端修改,session 只能在服务端设置,所以 session 更安全,一般用于验证用户登录状态。
  3. 有效期:cookie 可以设置任意时间;session 时间短、和当前标签页生命周期相同。
  4. 大小和个数限制:cookie 大小不超过 4KB,也有个数限制(20~几百,针对一个网站最多存20个);session 没有大小和个数限制。
  5. 服务器压力:cookie 压力小;session 压力大,尤其当访问量过多时、会占用过多服务器资源。因此对于并发用户多的场景,适合用 cookie

三、Token(令牌)

Token 是一串经过加密之后的字符串,相当于是用户的一种身份认证令牌。简单 token 的组成:uid(用户唯一的身份标识) + time(当前时间的时间戳) + sign(签名,是token的前几位以哈希算法压缩成的十六进制字符串)。

  • 服务端无状态化:基于 token 的用户认证是一种服务端无状态化的认证方式。服务端不用存放 token 数据,用解析 token 的计算时间换取 session 的存储空间,以减轻服务器的压力。

  • token 可以跨域:前提是不要放在cookie中。

  • 支持移动端设备:因为移动端对cookie、session的支持不太好,所以token可以有效兼容移动端设备。

(token 类似一张加密身份证,只要出示就知道是自己人;session 则是一种普通的身份证,每次都要根据 id 去查验)

免登录:有了 token 之后,用户就不需要每次访问网站都要先输入账号密码才能拿到数据了。而是只需要登录一次,以后拿着 token,服务器就知道你是哪一个用户了。

1. 身份认证流程

  1. 用户向服务端发送登录请求,服务端接收请求后会去验证账号、密码等信息。

  2. 验证成功后,服务端会生成一个 token 并发送给客户端,客户端会将它存储在本地(放在cookie不支持跨域,所以更好的方法是在请求头中加Authorization: Bearer <token>)。

  3. 客户端后续向服务端发送请求时,都需要携带该 token(放在请求头中)。然后服务端进行解析校验,验证成功就返回请求数据。

2. token 和 session区别

  1. 存储位置:客户端;服务端。
  2. 安全性:token更加安全,因为每个请求都有签名,还能防止 CSRF 攻击
  3. 服务端无状态化:token 使服务端无状态化,不会存储会话信息;session 则是一种记录服务端和客户端会话状态的机制,因此服务端是有状态的。

四、JWT

JSON Web Token(简称 JWT)是目前最流行的跨域认证解决方案,它也是一种认证授权机制。

传统方法例如 sessionID 存在缺点,例如当服务器是集群时无法做到单点登录。因为当在 A 服务器登录后生成的 sessionID 只能登录 A 服务器,访问 B 服务器时识别不了。而 JWT 可以做单点登录。

1. JWT 组成

  • Header(头部)
  • Payload(负载)
  • Signature(签名):由 header 和 payload 通过 base64 算法得到签名数据

Untitled.png

(1)Header 结构

{
	"alg": "HS256", // 告知服务端使用的加密算法
	"typ": "JWT" // 加密的类型,固定
}

(2)Payload 结构:可选项,还可以添加一些自定义字段。

Untitled (1).png

(3)签名

base64编码header + ‘.’ + base64编码payload,密钥secret 实际用的是对称加密。

类似 md5 这种摘要算法是不可逆的,不存在密钥去加密解密。

Untitled (2).png

2. JWT 认证流程

  1. 用户输入用户名/密码登录,服务端认证成功后,会返回给客户端一个 JWT;

  2. 客户端将 token 保存到本地(通常是 localStorage,也可以是 cookie);

  3. 当用户再次访问服务端时,需要在请求头的Authorization字段中使用Bearer模式添加 JWT(也可以放在cookie中发送,但是这样不能跨域)。然后服务端会检查请求头Authorization中的 JWT 信息,如果合法,则允许用户的行为。

3. JWT 的一种实现方式

  1. 服务端生成 JWT
    • 用户输入用户名/密码登录后,后台会在数据库中进行查找。如果能成功找到对应的一组数据,那么服务端可以使用 npm 的 jsonwebtoken 包生成 JWT

    • 然后将JWT(拷贝到ctx.body中)作为响应返回给客户端。

  2. 客户端存储 JWT
    • 客户端将接收的 token 存入 storage 中(通常是localStorage,也可以是cookie);

    • 之后向服务端发送请求时,需要在请求头中写入Authorization字段的Bearer模式以携带 token(这是一种约定的格式规范)。

      Authorization: Bearer <token>
      
  3. 服务端检查 JWT:检查AuthorizationJWT信息是否合法,合法则允许用户的行为。

4. JWT 和 token异同

  • 相同点:都使服务端无状态化。
  • 不同点:token 需要查数据库验证 token 是否有效,而 JWT 不用查库,直接在服务端进行校验(能否使用密钥解密)。这是因为用户的信息、加密的数据和过期时间等都在 JWT 里。
    • token:服务端验证客户端发来的token时,还需要查询数据库获取用户信息,然后验证token是否有效。
    • JWT:因为JWT本身就包含了用户信息和加密的数据,因此服务端验证时只需要使用密钥解密即可,不需要查询数据库。

五、比较

1. 注意点

  • cookie
    • 因为安全性低,尽量不要存储敏感数据,如密码、账户余额等;
    • 移动端对cookie的支持不是很好,而session又需要基于cookie实现,所以移动端常用的是token
  • token
    • 因为不需要 cookie,所以可以避免 CSRF 攻击

2. session、cookie、token

  1. 区别
    • 存储位置:session 在服务端,其他都在客户端。
    • 安全性:token > session > cookie。
    • 服务端有状态:token 无状态,其他都有状态。