JWT 基础使用教程

JWT 的概述

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

传统的身份验证

  • 用户向服务器发送用户名和密码
  • 验证服务器后,相关数据(如用户角色,登录时间等)将保存在当前会话中
  • 服务器向用户返回 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 的字符串结构

JWT 的内容为一个很长的字符串,字符之间通过点号 . 分隔分为三个子串。

每一个子串表示一个功能块,总共有三个部分:Header(头部)、Payload(负载)、Signature(签名)。

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

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

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

值得一提的是,非对称方式相较于对称方式更为安全,因为私钥只有认证服务器知道。

JWT 令牌与普通令牌的区别

  • JWT 令牌

    • 结构:JWT 令牌由三部分组成,用点号(.)分隔:
      • Header(头部):包含令牌类型和加密算法信息。
      • Payload(载荷):包含声明(Claims),即实际传输的数据,如用户 ID、过期时间等。
      • Signature(签名):用于验证令牌的真实性,确保令牌未被篡改。
    • 自包含:JWT 是自包含的,意味着所有必要的信息都包含在令牌本身中,不需要额外的数据库查询来验证和获取用户信息。
    • 无状态:由于 JWT 是自包含的,服务器可以通过解析令牌本身来验证用户,而不需要存储任何会话数据,从而实现无状态验证(即去中心化)。
    • 安全性:JWT 使用签名(通常是 HMAC、SHA256、RSA 签名方式)来保证数据的完整性和真实性,但不对数据进行加密。在数据传输过程中,如果需要加密,还需要使用 HTTPS 或者 JWE(JSON Web Encryption)。
  • 普通令牌

    • 结构:普通令牌通常是一个随机生成的字符串,没有固定的结构。
    • 依赖服务器存储:普通令牌通常不包含用户信息。服务器生成令牌后需要在数据库或内存中存储关联的用户信息和状态数据,每次请求时需要查找和验证。
    • 有状态:服务器必须保持会话状态,存储所有活跃令牌及其关联的用户数据,这意味着需要额外的存储和维护开销。
    • 安全性:普通令牌的安全性依赖于其随机性和服务器端的存储和验证机制。如果令牌本身没有加密或签名机制,数据完整性和真实性的保证依赖于服务器端的管理。
  • 优势总结

    • JWT 的优势:
      • 自包含:不需要服务器存储和管理会话数据(即去中心化)。
      • 无状态:适用于分布式系统,易于扩展。
      • 易于解析:基于标准的 JSON 格式,解析和生成都比较简单。
    • 普通令牌的优势:
      • 更适合简单和小型应用:不需要复杂的签名和解析机制。
      • 安全性可控:所有验证逻辑都在服务器端,容易统一管理。

JWT 的安全性

JWT 使用签名(通常是 HMAC、SHA256、RSA 签名方式)来保证数据的完整性和真实性,但不对数据进行加密。虽然 JWT 的 Payload(载荷)是以 Base64Url 编码的,但这种编码方式是可逆的,并不提供加密数据的功能,所以任何拥有 JWT 的人都可以解码并查看其内容。在数据传输过程中,如果需要加密,还需要使用 HTTPS 或者 JWE(JSON Web Encryption)。

Base64URL 算法

JWT 头和有效载荷序列化的算法一般都用到了 Base64URL。该算法和常见 Base64 算法类似,稍有差别。作为令牌的 JWT 可以放在 URL 中 (例如 /api.example/?token=xxx)。Base64 中用的三个字符是 "+","/" 和 "=",由于在 URL 中有特殊含义,因此 Base64URL 中对它做了替换,即 "=" 去掉,"+" 用 "-" 替换,"/" 用 "_" 替换,这就是 Base64URL 算法。

OAuth 2.0 与 JWT 的关系

  • OAuth 2.0 是一种认证授权的协议规范
  • JWT 是基于 Token 的安全认证协议的实现

OAuth 2.0 的认证服务器签发的 Token 可以使用 JWT 来实现,JWT 轻量且安全。

OAuth 2.0 与 SSO 的关系

SSO(Single Sign On,单点登录)是一种认证机制,允许用户使用单一的登录凭据(用户名和密码)访问多个相互信任的系统或应用程序。用户只需登录一次,即可访问所有相关系统,而不需要重复登录。

SSO 的主要优点

  1. 简化用户体验:用户只需一次登录,就能访问多个系统,减少了频繁登录的麻烦。
  2. 提高安全性:通过集中管理用户身份,可以更好地控制访问权限,并应用统一的安全策略。
  3. 降低管理成本:IT 管理员可以更加便捷地管理用户账户和权限,减少管理工作量。

实现 SSO 的常见技术和协议

  • Session 集中式存储:比如 Redis 缓存集中存储用户的 Session 信息。
  • OAuth 2.0:一种开放的授权标准,用于授权用户在第三方应用程序上访问用户资源,而不需要公开他们的用户名和密码。
  • OpenID Connect:基于 OAuth 2.0 协议的简单身份验证层,用于验证用户的身份并获取基本的用户信息。
  • SAML(安全断言标记语言):一种基于 XML 的标准,用于在身份提供者和服务提供者之间交换认证和授权数据。

SSO 与 OAuth 2.0 的关系

OAuth 2.0 是一种开放的授权标准,允许第三方应用程序在用户授权的情况下访问用户资源,而不需要暴露用户的凭据(如用户名和密码)。虽然 OAuth 2.0 主要用于授权,但它在实现 SSO 时也起到了重要作用,尤其是在以下方面:

  1. 令牌机制:OAuth 2.0 通过访问令牌(Access Token)和刷新令牌(Refresh Token)来管理用户会话,而且令牌可以使用 JWT 进行管理。这些令牌可以用于在不同的系统间共享用户认证信息,从而实现 SSO。
  2. 认证与授权:虽然 OAuth 2.0 主要设计用于授权,但它可以与 OpenID Connect 结合使用来实现认证。OpenID Connect 是在 OAuth 2.0 基础上增加了一层简单的身份认证协议,允许应用程序验证用户身份并获取用户基本信息。

SSO 与 OAuth 2.0 的使用场景

  • SSO 的使用场景通常是内部系统登录。一处登录,多处使用。
  • OAuth 2.0 的使用场景通常称为联合登录。一处注册,多处使用。

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

参考博客