JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
什么时候你应该用JWT
下列场景中使用JSON Web Token是很有用的:
- Authorization (授权)
- Information Exchange (信息交换)
JWT的组成
当你使用 JSON Web Token (JWT) 时,可以将其简单地理解为一个包含身份验证和授权信息的安全令牌。
-
头部(Header):JWT 的头部包含了两个重要的信息。第一个信息是令牌的类型,通常为 "JWT"。第二个信息是所使用的签名算法,用于验证令牌的完整性和可信度。头部会被进行 Base64 编码后添加到 JWT 的第一部分。
-
负载(Payload):负载是 JWT 的主要内容,包含一些声明(claims),即关于实体(通常是用户)和其他相关数据的陈述性语句。JWT 标准定义了一些常用的声明,例如 "iss"(签发者)、"exp"(过期时间)、"sub"(主题)等。此外,你还可以添加自定义的声明。负载会被进行 Base64 编码后添加到 JWT 的第二部分。
-
签名(Signature):签名用于验证 JWT 是否被篡改,并确保其来源可信。签名的生成依赖于头部中指定的签名算法和密钥。通常情况下,将编码后的头部和负载与密钥进行加密运算生成签名。签名会作为 JWT 的第三部分添加到令牌的末尾。
这三个部分使用句点(.)进行分隔,形成最终的 JWT。JWT 可以通过解码和验证签名来验证其完整性,并从负载中获取相关信息。
JSON Web Tokens (JWTs) 的工作原理
-
用户认证:当用户进行身份验证时,服务器会验证用户的身份,并生成一个包含用户信息和其他声明的 JWT。
-
JWT 发送:服务器将生成的 JWT 作为响应发送给客户端(通常是通过将 JWT 放置在响应的 HTTP 头部或响应体中)。
-
客户端存储:客户端收到 JWT 后,通常会将其存储在本地(例如,将 JWT 存储在浏览器的本地存储、会话存储或 cookie 中)。
-
请求发送:当客户端希望访问受保护的资源时,它会将 JWT 添加到每个请求中,通常通过将 JWT 放置在请求的 HTTP 头部的 Authorization 字段中。
-
服务器验证:服务器接收到带有 JWT 的请求后,会从请求中提取 JWT,并使用密钥进行验证。服务器首先检查 JWT 的签名是否有效以及是否被篡改过。然后,它会解码 JWT 的负载,并验证其中的声明和其他信息。
-
授权访问:如果 JWT 的签名有效且未被篡改,并且 JWT 中的声明满足服务器的要求(例如有效的身份验证、适当的权限等),服务器将允许客户端访问请求的资源。
-
刷新或终止令牌:如果 JWT 的过期时间较短,客户端可以使用刷新令牌或重新进行身份验证来获取新的 JWT。如果客户端希望终止访问,可以删除或失效 JWT。
JWT 的优点包括无状态性、可扩展性和跨域支持。由于 JWT 包含了所有必要的信息,服务器不需要在后续请求中查询数据库或会话存储,从而提高了性能和可伸缩性。
JWT怎么使用
首先,确保你已在 Node.js 项目中安装了 jsonwebtoken
库(使用 npm install jsonwebtoken
或 yarn add jsonwebtoken
)。
生成 JWT(在服务器端):
const jwt = require('jsonwebtoken');
// 用户信息
const user = {
id: 123,
username: 'john_doe',
role: 'admin'
};
// 生成 JWT
const secretKey = 'your_secret_key'; // 密钥,用于签名和验证 JWT
const expirationTime = '1h'; // JWT 过期时间
const jwtToken = jwt.sign(user, secretKey, { expiresIn: expirationTime });
console.log('Generated JWT:', jwtToken);
发送 JWT 给客户端:
在此示例中,假设你正在编写一个 Express.js 的路由处理程序。
app.post('/login', (req, res) => {
// 认证逻辑...
// 生成 JWT
const jwtToken = generateJWT();
// 发送 JWT 给客户端
res.status(200).json({ token: jwtToken });
});
客户端存储 JWT:
在客户端,你可以使用浏览器的本地存储(如 localStorage)来存储 JWT。
// 服务器端接收 JWT
const receivedToken = 'your_received_jwt';
// 存储 JWT 到本地存储
localStorage.setItem('jwt', receivedToken);
后续请求中发送 JWT:
在发送请求时,通过将 JWT 添加到请求的 Authorization 头部中来发送它。
const axios = require('axios');
// 从本地存储中获取 JWT
const jwtToken = localStorage.getItem('jwt');
// 发送请求并将 JWT 添加到 Authorization 头部
axios.get('https://api.example.com/protected-resource', {
headers: {
Authorization: `Bearer ${jwtToken}`
}
})
.then(response => {
// 处理响应
})
.catch(error => {
// 处理错误
});
服务器验证 JWT:
在服务器端,你可以使用相同的 jsonwebtoken
库来验证 JWT。
const jwt = require('jsonwebtoken');
// 获取从请求中获取的 JWT
const jwtToken = req.headers.authorization.split(' ')[1]; // 假设 JWT 在 Authorization 头部的 Bearer 方案中
// 验证 JWT
const secretKey = 'your_secret_key'; // 与生成 JWT 时使用的密钥相同
try {
const decoded = jwt.verify(jwtToken, secretKey);
console.log('Valid JWT:', decoded);
// 进一步处理和授权访问...
} catch (error) {
console.error('Invalid JWT:', error);
// 处理验证失败的情况...
}