关于 Token 认证系统的详细解析,包含核心概念、完整代码示例及对比总结

以下是关于 Token 认证系统 的详细解析,包含核心概念、完整代码示例及对比总结:
在这里插入图片描述


1. Token 令牌详解

定义:Token 是一种字符串,用于标识用户身份和权限。常用格式为 JWT(JSON Web Token),结构为 Header.Payload.Signature
在这里插入图片描述

JWT 结构示例
// Header(加密算法+类型)
{
  "alg": "HS256",
  "typ": "JWT"
}

// Payload(用户信息+声明)
{
  "sub": "1234567890",       // 用户ID
  "name": "John Doe",        // 用户名
  "iat": 1516239022,         // 签发时间(Unix时间戳)
  "exp": 1516325422         // 过期时间(iat + 有效期)
}

// Signature(签名:Header + Payload + 密钥)
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

2. 认证流程详解

步骤
  1. 用户登录:提交用户名/密码。
  2. 生成 Token:服务器验证成功后生成 JWT。
  3. 存储 Token:客户端保存 Token(如 localStorage)。
  4. 携带 Token:后续请求在 Authorization 头中携带 Bearer <token>
  5. 服务器验证:解析 Token,检查签名、过期时间等。

3. 验证流程详解

关键验证步骤
  1. 签名验证:确保 Token 未被篡改。
  2. 过期时间(exp):检查当前时间是否超过 exp
  3. 签发者(iss):验证 Token 是否由可信源签发。
  4. 权限(scope):检查用户是否有访问资源的权限。

4. Token 存储方式

常见存储方式对比
方式存储位置适用场景安全性
localStorage浏览器本地存储单页应用(SPA)易受 XSS 攻击
sessionStorage会话级存储临时存储(关闭页面失效)同上
CookieHTTP 头自动携带需要 HTTP 只读(Secure)可设置 HttpOnly 防 XSS
内存前端变量临时存储(页面刷新丢失)无存储风险

5. Token 过期处理

策略
  1. 短有效期 + 刷新 Token
    • Access Token:短有效期(如 15 分钟)。
    • Refresh Token:长有效期,用于获取新 Access Token。
  2. 自动重定向:Token 过期后跳转登录页。

完整代码示例

环境:Node.js + Express + JWT(jsonwebtoken 库)

1. 生成 Token(后端)
const jwt = require('jsonwebtoken');
const secret = 'your-256-bit-secret'; // 密钥需保密

// 用户登录成功后生成 Token
app.post('/login', (req, res) => {
  const user = { id: 1, name: 'John' };
  
  // 生成 Access Token(有效期 15 分钟)
  const accessToken = jwt.sign(
    { sub: user.id, name: user.name }, // Payload
    secret,
    { expiresIn: '15m' }              // 过期时间
  );
  
  // 生成 Refresh Token(有效期 7 天)
  const refreshToken = jwt.sign(
    { sub: user.id, type: 'refresh' },
    secret,
    { expiresIn: '7d' }
  );
  
  res.json({ accessToken, refreshToken });
});

2. 验证 Token 中间件(后端)
// 验证 Access Token 的中间件
function authMiddleware(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).send('未授权');
  }
  
  const token = authHeader.split(' ')[1];
  jwt.verify(token, secret, (err, decoded) => {
    if (err) {
      if (err.name === 'TokenExpiredError') {
        return res.status(401).send('Token 已过期');
      }
      return res.status(403).send('无效 Token');
    }
    req.user = decoded; // 将用户信息挂载到 req 对象
    next();
  });
}

3. 刷新 Token 接口(后端)
app.post('/refresh-token', (req, res) => {
  const refreshToken = req.body.refreshToken;
  if (!refreshToken) {
    return res.status(400).send('缺少 Refresh Token');
  }
  
  try {
    const decoded = jwt.verify(refreshToken, secret);
    if (decoded.type !== 'refresh') {
      throw new Error('无效的 Refresh Token');
    }
    
    // 生成新 Access Token
    const newAccessToken = jwt.sign(
      { sub: decoded.sub, name: 'John' }, // 假设用户信息不变
      secret,
      { expiresIn: '15m' }
    );
    
    res.json({ accessToken: newAccessToken });
  } catch (err) {
    res.status(401).send('Refresh Token 无效或过期');
  }
});

4. 前端存储与携带 Token
// 前端登录成功后存储 Token
localStorage.setItem('accessToken', response.accessToken);
localStorage.setItem('refreshToken', response.refreshToken);

// 发送请求时携带 Token
fetch('/api/data', {
  headers: {
    'Authorization': `Bearer ${localStorage.getItem('accessToken')}`
  }
})
.then(response => {
  if (response.status === 401) {
    // 自动刷新 Token
    return fetch('/refresh-token', {
      method: 'POST',
      body: JSON.stringify({ refreshToken: localStorage.getItem('refreshToken') })
    })
    .then(refreshResponse => {
      const newToken = refreshResponse.accessToken;
      localStorage.setItem('accessToken', newToken);
      // 重新发送原始请求
      return fetch('/api/data', { headers: { Authorization: `Bearer ${newToken}` } });
    });
  }
});

对比表格总结

内容描述代码示例片段
Token 生成使用 jwt.sign() 生成带签名的 Tokenjwt.sign(payload, secret, { expiresIn: '15m' })
Token 验证通过 jwt.verify() 检查签名和过期时间jwt.verify(token, secret, (err, decoded) => {...})
存储方式localStorage 适合 SPA,Cookie 需设置 HttpOnlylocalStorage.setItem('token', token);
过期处理短期 Access Token + 长期 Refresh Token刷新接口 /refresh-token 返回新 Access Token
中间件验证 Token 并挂载用户信息到请求对象req.user = decoded; next();

关键差异与最佳实践

  1. 安全性

    • Refresh Token:存储在 HTTP Only Cookie 中,防止 XSS。
    • Access Token:存储在 localStorage,需设置较短有效期。
  2. 过期策略

    • Access Token:短有效期(如 15 分钟)。
    • Refresh Token:长有效期(如 7 天),但需绑定设备指纹或 IP。
  3. 错误处理

    • 401 未授权:Token 无效或过期。
    • 403 禁止访问:签名错误或权限不足。

如果需要更复杂的场景(如 RBAC 权限控制),可扩展 Payload 中的 role 字段并在中间件中验证权限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱的叹息

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值