JSON Web Token 入门教程

JSON Web TokenJWT)是一种可以在多方之间安全共享数据的开放标准,JWT 数据经过编码和数字签名生成,可以确保其真实性,也因此 JWT 通常用于身份认证。这篇文章会介绍什么是 JWT,JWT 的应用场景以及组成结构,最后分析它的优点及局限性。

传统认证方式的问题

在介绍 JWT 之前,先看下传统认证方式有什么问题,这里的传统认证方式是指 Session-Cookie 方式。有小伙伴可能要说了,传统认证方式能有什么问题,如果有问题肯定是你代码写得不好。其实不是,有些问题存在于方案本身。

先来看一下传统的认证方式流程:

    1. 客户端输入用户名密码,点击登录。
    1. 服务端验证用户名密码,校验通过,服务端存储 Session 数据,如身份,权限。
    1. 服务端响应 Cookie,一般内容是一个 Session ID,客户端收到 Cookie 后存储。
    1. 客户端后续请求携带 Cookie 作为身份认证凭据,服务端验证 Cookie 得知用户身份。

这是常见的认证流程,但是这种认证方式存在下面几个问题。

状态存储负担

Session-Cookie 方式因为服务端要存储当前会话信息,而且必不可少, 这就额外增加了存储负担,而且在分布式系统中,还要考虑不同机器之间的会话状态同步问题。有时还需要部署独立的认证服务。不易维护。

跨域问题

基于 Cookie 会话的认证方式,在进行跨域请求时存在难点,Cookie 不会跟随跨域请求。认证信息带不过去,当然,聪明的小伙伴可以通过设置客户端参数,配置服务端参数等操作来允许跨域,不过有点麻烦了。

CSRF 攻击风险

CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种常见的 Web 安全漏洞。有些小伙伴不知道是什么意思,看下面流程:

    1. 你登录了 QQ 空间,传统认证方式,客户端成功存储了 Cookie。
    1. 你的 "好友X" 给你发了一个链接,标题 "专家:吃淀粉肠活不过三年"。
    1. 突然你感觉仿佛昨晚淀粉肠的香味还没散去,你迫不及待地点开了,没想到自动跳转到了 QQ 空间,你感觉莫名其妙,大失所望,立马关掉。
    1. 但是没想到的是这个跳转请求了空间说说发表接口,因为你之前登录过,Cookie 状态还在。说说直接发表成功了。那马上可能就有好友问你空间发的乱七八糟的内容是什么意思了。

QQ 空间曾经也确实出现过 CSRF 漏洞。

在解决这几个问题上,JWT 具有天然优势,它存储在客户端,服务端无状态。Token 可以不存在 Cookie 中,轻松跨域又减少了 CSRF 风险。

JWT 是什么

JWT(JSON Web Tokens)它定义了一种紧凑自包含 的方式用于在各方之间作为 JSON 对象安全地传递信息。紧凑意味着内容尽可能的短小。自包含意味着内容中包含了身份信息。这个信息可以用于身份认证 ,也可以用于信息交换 。由于信息会使用密钥进行数字签名 ,因此JWT 可以被验证以及信任。

JWT 应用场景

常见的 JWT 应用常见有 JWT 授权和信息交换:

  • 授权:JWT 被应用最多的场景,用户登录后服务端响应一个 JWT,后续的请求都携带 JWT内容,以此验证用户身份。使用 JWT 可以进行单点登录,可以跨域。

  • 信息交换:因为 JWT 需要使用密钥进行签名,因此使用 JWT 安全的传输信息也是一个好方法,签名可以确保消息发送人没有问题,确保消息没有被篡改。

JWT 组成结构

JWT 由小数点 分割的三部分组成,如 xxxxx.yyyyy.zzzzz,这三部分对应的是的标头(Header)、负载(Payload)、签名(Signature) ,每部分使用 Base64Url 进行编码,

下面是一个真实 JWT 示例:

JWT 示例

注意:JWT 为紧凑形式,没有换行,这里为了方便阅读,进行了换行。

标头 Header

Header 部分 Base64Url 解码后可以看到两个字段,alg 指定签名算法,typ 指定 Token 类型。

复制代码
{
  "alg": "HS256",
  "typ": "JWT"
}

对上述标头对象进行 Base64Url 编码以形成 JWT 的第一部分。

负载 Payload

第二部分中存放了实际需要的数据,用户可以自定义内容,如用户身份信息。

复制代码
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

同时 JWT 也规定了几个官方字段:

复制代码
iss (issuer):签发人
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
exp (expiration time):过期时间
iat (Issued At):签发时间
jti (JWT ID):编号

可以看到不管第一部分还是第二部分,字段名都是三位字母,这也是为了内容的紧凑。对 JWT 负载进行 Base64Url 编码以形成 JWT 的第二部分。

特别注意:由于只要 Base64Url 解码就可以看到第二部分内容,因此不能在 Payload 中存储敏感信息。

签名 Signature

签名 Signature 的生成依赖标头 Header负载 Payload ,同时要有拥有用于签名的密钥,因此签名可以用于验证 JWT 的发送者是否正确,并确保消息没有被篡改。

复制代码
Signature = HMACSHA256(
  base64UrlEncode(header) + '.' +
  base64UrlEncode(payload),
  secret)

JWT 官网也提供 JWT 在线解码验证工具[1],可以访问查看。

JWT 在线验证

JWT 身份认证

使用 JWT 进行身份认证的工作流程如下:

    1. 用户使用登录凭证(如用户名和密码)进行登录。
    1. 服务器验证凭证的正确性,并创建一个包含用户信息的 JWT。
    1. 服务器对 JWT 进行签名,然后将其发送回用户。
    1. 用户将 JWT 存储在客户端(如 localStorage),并在随后的请求中随同发送。如添加到请求头:Authorization: Bearer <token>
    1. 服务器在接收到请求后,验证 JWT 的签名并解析其内容,确认用户的身份,然后返回请求的数据。
    1. JWT 可能在一定时间后过期,用户需要重新登录获取新的 JWT。

JWT 的特点

JWT 有下面几个特点。

    1. 紧凑:JWT 设计十分紧凑,结果较小,可以在参数,请求头中传输。
    1. 自包含:JWT 自身包含了用户验证的所需信息,避免了多次查询数据库。
    1. 跨语言:JWT 使用 JSON 格式,现代编程语言都有对 JSON 的支持。
    1. 安全性 :JWT 需要使用密钥进行数据签名,密钥不泄露,JWT 就是安全的。但是因为 JWT 自包含和 Base64Url 编码特性,JWT 中的信息可以被直接读取,因此建议使用 HTTPS 协议。如果对安全性要求较高,还可以对 JWT 内容在进行一次加密(如 AES)。
    1. 分布式环境友好 :因为 JWT 在服务端无状态,因此 JWT 适用于单点登录,同时可以跨域
    1. 不可撤销:一旦 JWT 签发了,在有效期内将会一直有效,除非服务器增加额外逻辑来强制撤销某个 JWT Token,如黑名单机制。
    1. 性能问题:虽然避免了查询数据库,但是服务器仍需对每个请求中的 JWT 进行解码和验证,如果请求量巨大,这也可能成为性能瓶颈。

JWT 最佳实践

JWT 存在优点,也有很多风险与挑战,参考前人的最佳实践可以少走弯路。

    1. 内容紧凑最小化:最小限度的减少 JWT 负载中的内容,避免存储敏感数据,只存储重要数据。某些服务器不接受大于 8KB 的请求头。
    1. 验证必不可少:每次收到 JWT 都要进行验证,内容验证,过期时间验证。发行者验证。
    1. 使用 JWT 库:不要自己编写 JWT 类库,密码学和安全都是非常复杂的东西,使用专业的类库好过自己编写。
    1. JWT 过期时间:设计合理的过期时间,因为 JWT 一旦颁发,无法删除。过长的有效期存在风险。

总体而言,JWT 提供了一种相对简单且有效的方式来处理身份验证问题,但是需要注意JWT 安全性和细节问题,以确保 JWT 可以在应用中正确且安全地使用。

相关推荐
面朝大海,春不暖,花不开2 分钟前
自定义Spring Boot Starter的全面指南
java·spring boot·后端
得过且过的勇者y3 分钟前
Java安全点safepoint
java
小小小小宇17 分钟前
前端小tips
前端
小小小小宇26 分钟前
二维数组按顺时针螺旋顺序
前端
夜晚回家38 分钟前
「Java基本语法」代码格式与注释规范
java·开发语言
安木夕1 小时前
C#-Visual Studio宇宙第一IDE使用实践
前端·c#·.net
努力敲代码呀~1 小时前
前端高频面试题2:浏览器/计算机网络
前端·计算机网络·html
斯普信云原生组1 小时前
Docker构建自定义的镜像
java·spring cloud·docker
wangjinjin1801 小时前
使用 IntelliJ IDEA 安装通义灵码(TONGYI Lingma)插件,进行后端 Java Spring Boot 项目的用户用例生成及常见问题处理
java·spring boot·intellij-idea
wtg44521 小时前
使用 Rest-Assured 和 TestNG 进行购物车功能的 API 自动化测试
java