高安全架构 学习笔记(第 9 部分)
5.2 JWT 认证实现
javascript
// JWT 认证系统
const jwt = require('jsonwebtoken')
class JWTAuthentication {
constructor() {
this.secret = 'your-secret-key'
this.expiresIn = '7d'
this.refreshExpiresIn = '30d'
}
// 生成访问令牌
generateAccessToken(user) {
const payload = {
userId: user.id,
username: user.username,
role: user.role,
type: 'access'
}
return jwt.sign(payload, this.secret, {
expiresIn: this.expiresIn
})
}
// 生成刷新令牌
generateRefreshToken(user) {
const payload = {
userId: user.id,
type: 'refresh'
}
return jwt.sign(payload, this.secret, {
expiresIn: this.refreshExpiresIn
})
}
// 验证令牌
verifyToken(token) {
try {
const decoded = jwt.verify(token, this.secret)
return {
valid: true,
decoded
}
} catch (error) {
return {
valid: false,
error: error.message
}
}
}
// 刷新令牌
refreshToken(refreshToken) {
const result = this.verifyToken(refreshToken)
if (!result.valid || result.decoded.type !== 'refresh') {
throw new Error('无效的刷新令牌')
}
// 获取用户信息
const user = this.getUserById(result.decoded.userId)
// 生成新的访问令牌
const newAccessToken = this.generateAccessToken(user)
return {
accessToken: newAccessToken,
expiresIn: this.expiresIn
}
}
// 认证中间件
authenticate() {
return (req, res, next) => {
const token = this.extractToken(req)
if (!token) {
return res.status(401).json({
error: 'Unauthorized',
message: '未提供认证令牌'
})
}
const result = this.verifyToken(token)
if (!result.valid) {
return res.status(401).json({
error: 'Unauthorized',
message: '令牌无效或已过期'
})
}
// 将用户信息附加到请求对象
req.user = result.decoded
next()
}
}
// 提取令牌
extractToken(req) {
// 从 Authorization 头提取
const authHeader = req.headers.authorization
if (authHeader && authHeader.startsWith('Bearer ')) {
return authHeader.substring(7)
}
// 从查询参数提取
if (req.query.token) {
return req.query.token
}
// 从 Cookie 提取
if (req.cookies && req.cookies.token) {
return req.cookies.token
}
return null
}
// 获取用户信息
getUserById(userId) {
// 实际实现:从数据库查询
return {
id: userId,
username: 'user123',
role: 'user'
}
}
}
// 使用示例
const auth = new JWTAuthentication()
// 登录时生成令牌
app.post('/login', (req, res) => {
const { username, password } = req.body
// 验证用户名密码
const user = authenticateUser(username, password)
if (!user) {
return res.status(401).json({ error: '用户名或密码错误' })
}
// 生成令牌
const accessToken = auth.generateAccessToken(user)
const refreshToken = auth.generateRefreshToken(user)
res.json({
accessToken,
refreshToken,
expiresIn: auth.expiresIn
})
})
// 受保护的路由
app.get('/protected', auth.authenticate(), (req, res) => {
res.json({
message: '访问成功',
user: req.user
})
})