JWT 基础使用教程

JWT 概述

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。

传统的身份验证

  • 用户向服务器发送用户名和密码
  • 验证服务器后,相关数据(如用户角色,登录时间等)将保存在当前会话中
  • 服务器向用户返回 session_id,Session 信息都会写入到用户的 Cookie 中
  • 用户的每个后续请求都将通过在 Cookie 中取出 session_id 并传递给服务器
  • 服务器收到 session_id 并对比之前保存的数据,确认用户的身份

这种模式最大的问题是,没有分布式架构,无法支持横向扩展。如果使用一个服务器,该模式完全没有问题。但是,如果它是服务器群集或面向服务的跨域体系结构的话,则需要一个统一的 Session 数据库(Redis)来保存会话数据实现共享,如果保存 Session 的数据库(Redis)挂掉,整个认证体系都会挂掉。

JWT 的身份验证

JWT 的原则是在服务器身份验证之后,将生成一个 JSON 对象并将其发送给用户。之后,当用户与服务器通信时,客户在请求中带上 JSON 对象,服务器仅依赖于这个 JSON 对象来标识用户。为了防止用户篡改数据,服务器将在生成对象时添加签名。服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。具体的身份验证流程如下:

  • 用户发起登录请求,请求认证服务
  • 认证服务成功认证后,生成 JWT 令牌,并将 JWT 令牌写入到用户的 Cookie
  • 用户访问 Web 资源页面,带着 Cookie 到网关服务
  • 网关服务从 Cookie 获取并校验用户的 JWT 令牌,如果 JWT 令牌有效否则放行请求
  • 用户注销登录,请求认证服务,删除用户 Cookie 中的 JWT 令牌

JWT 与 传统身份验证比较

JWT 和传统的 Cookie/Session 会话管理相比较有着多方面的优势,因为 Cookie/Session 需要在 Web 服务器的 Session 里存放用户信息,然后通过客户端 Cookie 中存储的 session_id 来获取特定的用户信息,这个过程需要消耗 Web 服务器的内存和对客户端的要求比较严格(必须支持 Cookie),而 JWT 最大的特性在于就是无状态、去中心化,所以 JWT 更适用分布式的场景,不需要在多台服务器做会话同步这种消耗服务器性能的操作。另外 JWT 和 Redis + Token 这两种会话管理方案需要根据项目情况选择,别用了 JWT 还使用 Redis 存储的,因为这种做法对 JWT 来说就是 “伤害不大,但侮辱性极强” 的做法,相当于无视 JWT 的 “无状态” 特性。

JWT 字符串结构

JWT 字符串由 Header(头部)、Payload(负载)、Signature(签名)三部分组成:

  • Header: JSON 对象,用来描述 JWT 的元数据,alg 属性表示签名的算法,typ 标识 token 的类型
  • Payload: JSON 对象,重要部分,除了默认的字段,还可以扩展自定义字段,比如用户 ID、姓名、角色等等
  • Signature: 对 Header、Payload 这两部分进行签名,认证服务器使用私钥签名,然后在资源服务器使用公钥验签,防止数据被人动了手脚

JWT 签名有对称和非对称两种方式:

  • 对称方式:认证服务器和资源服务器使用同一个密钥进行加签和验签 ,默认算法 HMAC
  • 非对称方式:认证服务器使用私钥加签,资源服务器使用公钥验签,默认算法 RSA

非对称方式相较于对称方式更为安全,因为私钥只有认证服务器知道

JWT 开源库的使用

Gateway + JWT 实现统一的认证授权

参考博客