JWT入门
JWT简介
JWT (JSON Web Token) 是一种开放标准,用于在各方之间安全地传输信息。它是一个紧凑、URL安全的令牌,常用于身份验证和信息交换。
JWT的结构
JWT由三部分组成,用点(.)分隔:
Header.Payload.Signature
实际示例:用户登录系统
场景描述
假设我们有一个在线购物网站,用户需要登录后才能查看订单历史。
1. JWT生成过程(用户登录)
步骤1:用户提交登录信息
// 用户登录请求
POST /api/login
{
"username": "[email protected]",
"password": "password123"
}
步骤2:服务器验证用户信息并生成JWT
// 服务器端代码示例 (Node.js)
const jwt = require('jsonwebtoken');
// 验证用户凭据后
const user = {
id: 12345,
username: "[email protected]",
role: "customer"
};
// JWT Header
const header = {
"alg": "HS256",
"typ": "JWT"
};
// JWT Payload
const payload = {
"sub": "12345", // subject (用户ID)
"username": "[email protected]",
"role": "customer",
"iat": 1640995200, // issued at (签发时间)
"exp": 1641081600 // expiration time (过期时间)
};
// 生成JWT
const secretKey = "your-secret-key";
const token = jwt.sign(payload, secretKey, { expiresIn: '24h' });
// 返回给客户端
res.json({
"success": true,
"token": token,
"user": {
"id": 12345,
"username": "[email protected]"
}
});
生成的JWT示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NSIsInVzZXJuYW1lIjoiYWxpY2VAZXhhbXBsZS5jb20iLCJyb2xlIjoiY3VzdG9tZXIiLCJpYXQiOjE2NDA5OTUyMDAsImV4cCI6MTY0MTA4MTYwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
2. JWT使用过程(访问受保护资源)
步骤1:客户端存储JWT
// 前端代码
localStorage.setItem('token', response.data.token);
步骤2:客户端发送请求时携带JWT
// 访问订单历史
GET /api/orders
Headers: {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
步骤3:服务器验证JWT
// 服务器端中间件
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) {
return res.sendStatus(401); // Unauthorized
}
jwt.verify(token, secretKey, (err, user) => {
if (err) {
return res.sendStatus(403); // Forbidden
}
req.user = user; // 将用户信息添加到请求对象
next();
});
};
// 受保护的路由
app.get('/api/orders', authenticateToken, (req, res) => {
// 可以安全地使用 req.user 中的用户信息
const userId = req.user.sub;
const orders = getOrdersByUserId(userId);
res.json({
"success": true,
"orders": orders
});
});
JWT的主要作用
1. 身份验证 (Authentication)
- 用户登录后获得JWT
- 后续请求携带JWT证明身份
- 无需每次都查询数据库验证用户
2. 授权 (Authorization)
// JWT中包含角色信息
const payload = {
"sub": "12345",
"username": "[email protected]",
"role": "admin", // 管理员角色
"permissions": ["read", "write", "delete"]
};
// 服务器端权限检查
const requireAdmin = (req, res, next) => {
if (req.user.role !== 'admin') {
return res.status(403).json({ error: 'Admin access required' });
}
next();
};
3. 信息交换
// JWT可以安全地传输用户信息
const userInfo = {
"sub": "12345",
"username": "[email protected]",
"department": "sales",
"preferences": {
"language": "zh-CN",
"theme": "dark"
}
};
JWT的优势
1. 无状态性
// 传统Session方式需要服务器存储
// sessions = {
// "session123": { userId: 12345, username: "alice" }
// }
// JWT方式:所有信息都在token中,服务器无需存储
2. 跨域支持
// 可以在不同域名间使用
// api.example.com 生成的JWT
// 可以在 app.example.com 中使用
3. 移动端友好
// 移动应用中存储JWT
// 不依赖Cookie机制
const token = await AsyncStorage.getItem('jwt_token');
完整的前端使用示例
// 前端完整示例
class AuthService {
constructor() {
this.token = localStorage.getItem('token');
}
async login(username, password) {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (data.success) {
this.token = data.token;
localStorage.setItem('token', this.token);
return true;
}
return false;
}
async fetchOrders() {
const response = await fetch('/api/orders', {
headers: {
'Authorization': `Bearer ${this.token}`
}
});
if (response.status === 401) {
// Token过期,重新登录
this.logout();
window.location.href = '/login';
return;
}
return await response.json();
}
logout() {
this.token = null;
localStorage.removeItem('token');
}
isAuthenticated() {
if (!this.token) return false;
try {
const payload = JSON.parse(atob(this.token.split('.')[1]));
return payload.exp > Date.now() / 1000;
} catch (e) {
return false;
}
}
}
安全注意事项
1. 敏感信息不要放在JWT中
// ❌ 错误:不要在JWT中存储密码
const badPayload = {
"username": "alice",
"password": "password123" // 危险!
};
// ✅ 正确:只存储必要的非敏感信息
const goodPayload = {
"sub": "12345",
"username": "alice",
"role": "customer"
};
2. 使用HTTPS传输
// 确保在生产环境中使用HTTPS
// JWT在网络传输中是Base64编码,不是加密
3. 设置合理的过期时间
// 短期访问token
const accessToken = jwt.sign(payload, secret, { expiresIn: '15m' });
// 长期刷新token
const refreshToken = jwt.sign(payload, secret, { expiresIn: '7d' });
通过这个完整的示例,你可以看到JWT在现代Web应用中如何简化身份验证流程,提供无状态的认证机制,并支持分布式系统的扩展。