NodeJs学习日志(7):JWT学习
八股文
什么是JWT?
JWT(JSON Web Token)是一种 基于 JSON 的开放标准(RFC 7519),用于在客户端和服务器之间安全地传递声明(Claims)。它本质上是一个经过加密签名的字符串,包含了用户身份信息和其他元数据,服务器无需存储会话状态,仅通过验证 Token 的有效性即可完成身份认证。
JWT 的结构(三段式)
一个完整的 JWT 由 Header(头部)、Payload(载荷)、Signature(签名) 三部分组成,用 . 分隔,格式如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwidXNlcklkIjoiMTIzNDU2IiwiaWF0IjoxNzM0NTYwMDYxLCJleHAiOjE3MzQ1NjM2NjF9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- Header(头部)
指定算法和令牌类型,默认使用 Base64 编码(可逆)
{
"alg": "HS256", // 加密算法(如 HS256、RS256)
"typ": "JWT" // 令牌类型
}
-
Payload(载荷)
存储核心数据(用户信息、过期时间等),同样使用 Base64 编码(注意:Base64 是编码不是加密,不要存储敏感信息!)
内置的标准声明(可选):
iat:令牌签发时间(时间戳)
exp:令牌过期时间(时间戳)
sub:令牌主题(通常是用户 ID)
自定义声明:如 username、userId 等业务字段 -
Signature(签名)
由 Header + Payload + 密钥(Secret Key)通过指定算法加密生成,用于验证令牌的完整性和真实性。
JWT 的核心功能
- 无状态身份认证
服务器无需存储用户会话信息,仅通过验证 Token 签名即可确认用户身份,降低了服务器存储压力,尤其适合分布式系统和微服务。 - 跨域认证
Token 是自包含的,可通过 HTTP 请求头(如 Authorization: Bearer )传递,轻松支持跨域场景(如前端部署在 xxx.com,后端部署在 api.xxx.com)。 - 数据传输
Payload 可携带非敏感业务数据(如用户昵称、角色),减少后端查询数据库的次数,提升接口性能。 - 令牌刷新
支持在 Token 过期前或过期后,通过旧 Token 生成新 Token(需保证旧 Token 未被篡改),避免用户频繁登录。
使用
安装
npm install jsonwebtoken
代码
const jwt = require('jsonwebtoken');
// 生成强密钥(生产环境应从环境变量读取)
const generateSecretKey = () => {
return crypto.randomBytes(64).toString('hex');
};
console.log("生成密钥:", generateSecretKey());
//jwt配置,
const JWT_OPTIONS = {
SECRET_KEY: "secret-key", // 密钥
EXPIRES_IN: '1h',//过期时间
ALGORITHM: 'HS256' // 加密方式
};
//等待加密的载荷
const payload = {
username: "admin",
userId: "123456"
}
// 生成JWT
function generateToken(payload) {
const token = jwt.sign(payload, JWT_OPTIONS.SECRET_KEY, {
expiresIn: JWT_OPTIONS.EXPIRES_IN,
algorithm: JWT_OPTIONS.ALGORITHM
});
return token;
}
let token = generateToken(payload);
console.log("生成的Token:", token);
// 验证JWT
function verifyToken(token) {
try {
const decoded = jwt.verify(token, JWT_OPTIONS.SECRET_KEY, {
algorithms: [JWT_OPTIONS.ALGORITHM]
});
console.log("Token验证成功:", decoded);
return { valid: true, decoded };
} catch (error) {
if (error.name === 'TokenExpiredError') {
console.log("Token已过期:", error.expiredAt);
return { valid: false, error: 'TOKEN_EXPIRED' };
} else if (error.name === 'JsonWebTokenError') {
console.log("Token无效:", error.message);
return { valid: false, error: 'INVALID_TOKEN' };
} else {
console.log("Token验证失败:", error.message);
return { valid: false, error: 'VERIFICATION_FAILED' };
}
}
}
verifyToken(token);
// 刷新JWT
function refreshToken(token) {
const verificationResult = verifyToken(token);
if (!verificationResult.valid && verificationResult.error !== 'TOKEN_EXPIRED') {
throw new Error('无法刷新无效的Token');
}
// 即使token过期,我们也尝试解码获取payload(不验证过期)
const decoded = jwt.decode(token);
if (!decoded) {
throw new Error('无法解码Token');
}
// 移除原有的过期时间和其他jwt属性,保留原始数据
const { iat, exp, ...payload } = decoded;
console.log("decoded" + JSON.stringify(decoded));
const { username, userId } = decoded;
console.log("username" + username);
console.log("userId" + userId);
const newToken = generateToken(payload);
console.log("刷新的Token:", newToken);
return newToken;
}
refreshToken(token);
669

被折叠的 条评论
为什么被折叠?



