目录
- 前言
- 1. 基本知识
- 2. JWT验证过程
- 3. Demo
前言
对于Java的基本知识推荐阅读:
- java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
- 【Java项目】实战CRUD的功能整理(持续更新)
1. 基本知识
紧凑的、URL-safe 的表示方式,通常用于认证和信息交换
JWT 由三部分组成,用点号分隔:
- Header(头部):通常包括令牌的类型(JWT)和所使用的签名算法(如 HMAC SHA256 或 RSA)
- Payload(负载):包含要传递的声明(Claims),例如用户信息、权限等
- Signature(签名):使用头部中指定的算法对编码后的头部和负载进行签名,以确保信息的完整性和来源的真实性
为了更好的解析jwt的组成,我们找一个网址,查看本地存储所得到的jwt,去解析:https://jwt.io/
截图如下:(为避免不必要,已将多数数据隐藏)
一、Header(头部)
- 类型(typ):通常为 JWT,表示这是一个 JSON Web Token
- 算法(alg):指定用于签名的算法
例如,HS256 代表 HMAC SHA-256 算法
头部被 Base64 URL 编码后,通常如下所示:
{"alg": "HS256","typ": "JWT"
}
二、Payload(负载)
- 注册声明(Registered Claims):这些是预定义的声明,如 exp(过期时间)、iss(发行者)、sub(主题)等
- 公共声明(Public Claims):自定义声明,可以与 IANA 注册表中的标准声明名称进行匹配
- 私有声明(Private Claims):应用程序之间自定义的声明,用于传递特定的信息
jti
:唯一的令牌标识符,用于防止重放攻击
三、 Signature(签名)
签名部分用于验证消息的完整性和来源,通过对编码后的头部和负载进行 HMAC SHA-256 签名生成的
公式如下:
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),your-256-bit-secret
)
验证JWT是否被修改的过程:
-
解码 Header 和 Payload
将 Base64 URL 编码后的 Header 和 Payload 部分进行解码 -
验证 Signature
使用密钥(your-256-bit-secret)和指定的算法(HS256)对 Header 和 Payload 进行签名,生成一个签名部分
验证生成的签名与 JWT 的实际签名部分是否一致,以确定令牌是否被篡改
总的来说JWT 的各部分作用:
部分 | 描述 | 作用 |
---|---|---|
Header | 包含令牌的元数据,如类型和算法 | 指定令牌类型和签名算法 |
Payload | 包含声明信息,包括注册声明、公共声明和私有声明 | 传递用户和权限信息等 |
Signature | 使用头部中指定的算法和密钥对 Header 和 Payload 进行签名 | 验证令牌的完整性和来源 |
JWT 与其他认证机制对比
特性/机制 | JWT | Session-Based Authentication | OAuth2 | API Key |
---|---|---|---|---|
认证类型 | 无状态(Stateless) | 有状态(Stateful) | 无状态(Stateless) | 无状态(Stateless) |
存储位置 | 客户端存储(通常在本地存储或 Cookie 中) | 服务器端存储会话信息 | 通常使用访问令牌存储在客户端或服务器端 | 客户端存储(通常在请求头中) |
扩展性 | 适合分布式系统和微服务架构 | 不适合扩展到分布式系统或微服务 | 支持授权和资源访问控制,适合大型应用 | 适合简单的 API 访问控制 |
安全性 | 签名保证数据完整性,但需要 HTTPS 保护 | 服务器端存储提供安全性,但会话劫持问题 | OAuth2 提供了多层安全性(如授权码流、客户端流等) | 安全性较低,容易被暴露 |
易用性 | 易于在客户端和服务器端使用,支持多种语言和平台 | 服务器需要管理会话,较复杂 | 需要处理授权过程,较复杂 | 简单直接,但不支持细粒度的权限控制 |
过期管理 | 内置过期时间,通常在令牌中指定 | 需要服务器端管理会话过期 | 通过刷新令牌机制管理 | 需要手动管理过期和权限 |
适用场景 | 适合 API 身份验证、微服务架构 | 适合传统的 web 应用 | 适合第三方应用授权、复杂的用户权限控制 | 适合简单的服务或接口调用 |
2. JWT验证过程
在客户端和服务器之间安全地传递信息的机制,在身份验证过程中,JWT 用于证明用户的身份,并在服务器上进行授权
精简的步骤如下:
一、用户登录
1.1 用户提供凭据(如用户名和密码)到服务器
1.2 服务器验证凭据,生成 JWT 如果凭据有效,服务器生成一个 JWT。该令牌通常包含用户的身份信息(如用户ID、角色等)以及其他声明(如过期时间 exp)
1.3 服务器返回 JWT 给客户端
二、客户端使用 JWT
客户端将 JWT 存储在本地(如 localStorage)
客户端在请求受保护资源时,将 JWT 附加到请求的 Authorization 头中
三、服务器验证 JWT
服务器接收请求,提取并解码 JWT。(服务器从请求的 Authorization 头中提取 JWT,并对其进行 Base64 解码以获取 Header 和 Payload 部分)
验证 JWT 签名和有效性(如过期时间)。(服务器使用预先定义的密钥和算法(如 HMAC SHA-256)对 JWT 的签名进行验证,以确保令牌没有被篡改)
如果有效,授权访问资源;否则,返回 401 错误
四、处理请求
服务器根据 JWT 中的信息处理请求并返回数据
客户端处理服务器响应
基本的交互形式如下:
登录请求
客户端请求:
POST /login HTTP/1.1
Host: example.com
Content-Type: application/json{"username": "john","password": "password123"
}
服务器响应:
{"access_token": "eyJhbGciOiAiSFMyNTYiLCAiaWF0IjogMTYzNjIxxxxx.eyJzdWIiOiIxMjM0NTY3ODkwIiwgIm5hbWUiOiJKb2huIERvZSIsICJpYXQiOiAxNjM2MjQ3ODYxLCAiZXhwIjogMTYzNjI1MxxxxxxHRJ7to7Yb2PTthg4civ9kW-FwcE"
}
访问受保护资源
客户端请求:
GET /protected-resource HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGciOiAiSFMyNTYiLCAiaWF0IjogMTYzNjI0Nzg2MSxxxxxx6IDE2MzYyNTExNjF9.eyJzdWIiOiIxMjM0NTY3ODkwIiwgIm5hbWUiOiJKb2huIERvZSIsICJpYXQiOiAxNjM2MjQ3ODYxLCxxxxxxjI1MTE2MX0._XxZ9mOeA9v0qjPvHRJ7to7Yb2PTthg4civ9kW-FwcE
服务器响应:
{"data": "This is a protected resource."
}
3. Demo
使用 Node.js 和 jsonwebtoken 库的简单示例,演示如何生成和验证 JWT:
const jwt = require('jsonwebtoken');// 密钥,用于签名和验证 JWT
const secretKey = 'your-very-secure-secret';// 生成 JWT
function generateToken(payload) {return jwt.sign(payload, secretKey, { expiresIn: '1h' });
}// 验证 JWT
function verifyToken(token) {try {const decoded = jwt.verify(token, secretKey);return { valid: true, decoded };} catch (error) {return { valid: false, error: error.message };}
}// 示例使用
const payload = { userId: 123, role: 'admin' };
const token = generateToken(payload);
console.log('Generated JWT:', token);const verificationResult = verifyToken(token);
console.log('Verification Result:', verificationResult);