«

JWT入门

daidaini 发布于 阅读:43 程序员学习


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)

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应用中如何简化身份验证流程,提供无状态的认证机制,并支持分布式系统的扩展。

web http