【一文看懂token和session】

token机制

Token(令牌)是前后端身份验证的核心机制,用于在用户登录后证明其身份,避免频繁输入账号密码。其运行流程可分为生成、传输、验证、失效四个阶段,以下是详细解析:

一、Token 的核心作用

  • 身份凭证:用户登录成功后,服务器生成一个唯一 Token,作为用户后续请求的 “通行证”。
  • 无状态验证:服务器无需存储用户会话信息(区别于传统的 Session 机制),仅通过 Token 即可验证身份,适合分布式系统。

二、完整运行流程

1. 生成 Token(登录阶段)
  • 用户提交凭证:用户在登录页面输入账号密码(或其他验证信息,如手机号验证码),前端将数据发送到后端登录接口。

  • 服务器验证并生成 Token

    • 后端验证账号密码的有效性。

    • 验证通过后,服务器根据用户信息(如用户 ID、角色、权限等)生成 Token。

    • Token 通常通过加密算法(如 JWT 的 HS256、RS256)生成,包含三部分:

      • Header(头部):指定加密算法(如{"alg": "HS256", "typ": "JWT"})。
      • Payload(载荷):存储用户核心信息(如{"userId": 123, "role": "admin", "exp": 1620000000}exp为过期时间)。
      • Signature(签名):用服务器密钥对 Header 和 Payload 加密后的字符串,确保 Token 未被篡改。
    • 服务器将生成的 Token 返回给前端。

    // 后端(Node.js示例,使用jsonwebtoken库)
    const jwt = require('jsonwebtoken');
    const secret = 'server-secret-key'; // 服务器私有密钥
    
    // 登录接口
    app.post('/login', (req, res) => {
      const { username, password } = req.body;
      // 假设验证通过,获取用户信息
      const user = { id: 1, username: 'admin', role: 'admin' };
      // 生成Token,设置2小时后过期
      const token = jwt.sign(
        { userId: user.id, role: user.role },
        secret,
        { expiresIn: '2h' }
      );
      res.json({ code: 200, token }); // 返回Token给前端
    });
    
2. 存储 Token(前端)

前端收到 Token 后,需存储在本地,常用方式:

  • localStorage:持久化存储(关闭浏览器不丢失,适合长期登录),但存在 XSS 攻击风险。

  • sessionStorage:会话级存储(关闭浏览器后删除,适合临时登录)。

  • HTTP-only Cookie:通过后端设置HttpOnly: true,避免 JS 访问,防御 XSS 攻击,同时可设置Secure: true(仅 HTTPS 传输)和SameSite(防御 CSRF)。

    // 前端登录成功后存储Token
    axios.post('/login', { username, password }).then(res => {
      const { token } = res.data;
      localStorage.setItem('token', token); // 存储到localStorage
    });
    
3. 传输 Token(请求阶段)

用户后续访问需要权限的接口时,前端需在请求中携带 Token,主流方式:

  • HTTP 请求头(推荐):通过Authorization字段携带,格式通常为Bearer <token>

  • URL 参数:(不推荐,存在安全风险,易暴露在日志中)。

    // 前端请求拦截器(Axios示例)
    axios.interceptors.request.use(config => {
      const token = localStorage.getItem('token');
      if (token) {
        config.headers.Authorization = `Bearer ${token}`; // 添加到请求头
      }
      return config;
    });
    
4. 验证 Token(服务器)
  • 服务器解析 Token:后端接口收到请求后,从Authorization头中提取 Token。

  • 验证 Token 有效性

    • 检查签名是否正确(用服务器密钥验证,确保未被篡改)。
    • 检查是否过期(验证exp字段)。
    • 解析 Payload 中的用户信息(如用户 ID、角色),确认用户有权限访问接口。
  • 处理验证结果

    • 验证通过:正常处理请求,返回数据。
    • 验证失败(如 Token 无效、过期):返回 401(未授权)或 403(禁止访问),前端跳转至登录页。
    // 后端验证中间件(Node.js示例)
    const authMiddleware = (req, res, next) => {
      const authHeader = req.headers.authorization;
      if (!authHeader || !authHeader.startsWith('Bearer ')) {
        return res.status(401).json({ message: '未提供Token' });
      }
      const token = authHeader.split(' ')[1];
      try {
        // 验证Token并解析用户信息
        const decoded = jwt.verify(token, secret);
        req.user = decoded; // 将用户信息挂载到请求对象
        next(); // 验证通过,继续处理请求
      } catch (err) {
        return res.status(401).json({ message: 'Token无效或已过期' });
      }
    };
    
    // 保护需要权限的接口
    app.get('/user/info', authMiddleware, (req, res) => {
      // 使用解析出的用户信息处理请求
      res.json({ userId: req.user.userId, role: req.user.role });
    });
    
5. Token 失效与刷新
  • 主动失效:用户退出登录时,前端删除本地 Token,后端可通过 “黑名单” 机制(如 Redis 存储失效 Token)强制使已颁发的 Token 失效(适用于安全场景,如账号被盗)。

  • 过期刷新:为避免用户频繁登录,可采用 “双 Token 机制”:

    • Access Token:短期有效(如 2 小时),用于接口访问。
    • Refresh Token:长期有效(如 7 天),用于 Access Token 过期后获取新的 Access Token。
    • 流程:Access Token 过期时,前端用 Refresh Token 调用刷新接口,获取新的 Access Token,继续使用。

三、Token 的优势与风险

优势:
  • 无状态:服务器无需存储会话,减轻服务器压力,适合分布式系统。
  • 跨域支持:相比 Cookie,Token 在跨域请求中更易处理(如前后端分离架构)。
  • 扩展性:可在 Payload 中携带用户角色、权限等信息,减少数据库查询。
风险:
  • XSS 攻击:若 Token 存储在 localStorage,可能被恶意脚本窃取(需配合 HTTPS、CSP 策略防御)。
  • 无法即时回收:Token 一旦颁发,在过期前始终有效(除非用黑名单机制)。
  • Payload 可解码:JWT 的 Payload 是 Base64 编码(非加密),不可存储敏感信息(如密码)。

总结

Token 的运行核心是 “一次验证,多次使用”:用户登录时生成加密 Token,后续请求通过 Token 证明身份,服务器通过解密和签名验证确认合法性。实际应用中需结合存储方式(如 HTTP-only Cookie)、刷新机制(如双 Token)和安全策略(如 HTTPS),平衡安全性和用户体验。


分割线


session机制

传统的 Session(会话)机制是早期 Web 开发中实现用户身份认证的主流方式,核心是通过服务器存储用户状态来维持登录会话。其运行流程围绕会话创建、状态存储、身份验证三个核心环节,以下是详细解析:

一、Session 的核心原理

Session 机制基于 “服务器存储用户状态” 的思想:用户登录后,服务器为其创建一个唯一的会话(Session),并通过一个标识(Session ID)与用户绑定。后续请求中,用户通过携带 Session ID 证明身份,服务器通过 ID 查找对应的会话状态,实现身份验证。

二、完整运行流程

1. 会话创建(登录阶段)
  • 用户提交凭证:用户在登录页面输入账号密码,前端将数据发送到后端登录接口。

  • 服务器验证并创建 Session

    • 后端验证账号密码有效性。
    • 验证通过后,服务器创建一个Session 对象(存储在服务器内存、数据库或缓存中),包含用户信息(如用户 ID、角色、登录时间等)。
    • 服务器生成一个唯一的Session ID(通常是随机字符串,如 sess_abc123xyz),作为该 Session 的标识。
    • 服务器将 Session ID 发送给前端(通常通过 Cookie 传递)。
    // 后端(Node.js + Express 示例)
    const express = require('express');
    const session = require('express-session');
    const app = express();
    
    // 配置 Session 存储(默认存内存,生产环境用 Redis 等)
    app.use(session({
      secret: 'server-secret', // 用于加密 Session ID 的密钥
      resave: false,
      saveUninitialized: true,
      cookie: { secure: false } // 开发环境关闭 HTTPS 要求
    }));
    
    // 登录接口
    app.post('/login', (req, res) => {
      const { username, password } = req.body;
      // 假设验证通过,获取用户信息
      const user = { id: 1, username: 'admin' };
      // 将用户信息存入 Session(服务器端)
      req.session.user = user;
      // Session ID 会自动通过 Cookie 发送给前端
      res.json({ code: 200, message: '登录成功' });
    });
    
2. 存储 Session ID(前端)

前端收到服务器返回的 Session ID 后,通常通过 Cookie 自动存储(由浏览器管理):

  • 服务器在响应头中设置 Set-Cookie 字段,例如:
    Set-Cookie: connect.sid=sess_abc123xyz; Path=/; HttpOnly; Max-Age=86400

  • 浏览器会将该 Cookie 保存,并在后续请求中自动携带(无需前端手动处理)。

    // 响应头示例(服务器 → 浏览器)
    HTTP/1.1 200 OK
    Set-Cookie: connect.sid=sess_abc123xyz; Path=/; HttpOnly
    Content-Type: application/json
    
3. 身份验证(请求阶段)

用户访问需要权限的接口时,浏览器自动携带 Session ID(通过 Cookie),服务器通过 ID 验证身份:

  • 前端发送请求:请求头中自动包含 Session ID 的 Cookie,例如:
    Cookie: connect.sid=sess_abc123xyz

  • 服务器验证 Session

    • 服务器从请求 Cookie 中提取 Session ID。
    • 根据 ID 查找对应的 Session 对象(如从内存、Redis 中读取)。
    • 若找到 Session 且状态有效(未过期),则确认用户身份,允许访问接口。
    • 若未找到 Session(如 ID 无效、已过期),则拒绝访问,要求重新登录。
    // 后端验证接口(需登录才能访问)
    app.get('/user/info', (req, res) => {
      // 从 Session 中获取用户信息(服务器已通过 Session ID 找到对应 Session)
      if (req.session.user) {
        // 验证通过,返回用户信息
        res.json({ user: req.session.user });
      } else {
        // 未登录,返回 401 错误
        res.status(401).json({ message: '请先登录' });
      }
    });
    
4. 会话销毁(退出登录)
  • 主动退出:用户点击退出登录时,前端发送退出请求,服务器销毁对应的 Session 对象,并清除 Session ID 对应的 Cookie。

  • 自动过期:服务器为 Session 设置过期时间(如 2 小时),过期后自动销毁,用户需重新登录。

    // 退出登录接口
    app.post('/logout', (req, res) => {
      // 销毁当前 Session
      req.session.destroy(err => {
        if (err) return res.status(500).json({ message: '退出失败' });
        // 清除客户端 Cookie
        res.clearCookie('connect.sid');
        res.json({ code: 200, message: '退出成功' });
      });
    });
    

三、Session 的存储方式

服务器存储 Session 的位置决定了其扩展性和可靠性:

  1. 内存存储:默认方式,优点是快,缺点是服务器重启后 Session 丢失,且不支持分布式系统(多服务器间无法共享 Session)。
  2. 文件存储:将 Session 写入服务器文件,解决内存存储的丢失问题,但性能较差。
  3. 数据库存储:如 MySQL、MongoDB,适合需要持久化的场景,但读写性能一般。
  4. 缓存存储:如 Redis、Memcached,性能优异且支持分布式(多服务器可共享 Redis 中的 Session),是生产环境的主流选择。

四、Session 与 Token 的核心区别

对比维度Session 机制Token 机制
状态存储位置服务器端(内存 / 数据库 / Redis)客户端(localStorage/Cookie)
验证方式通过 Session ID 查服务器状态直接解析 Token 验证签名
扩展性分布式系统需共享 Session 存储无状态,天然支持分布式
跨域支持受 Cookie 跨域限制无限制,可在请求头中传递
安全性依赖依赖 Cookie 安全配置依赖 Token 加密和传输安全

总结

Session 机制的核心是 “服务器保存状态,客户端携带 ID”:通过 Session ID 关联用户与服务器端的会话状态,实现身份验证。其优点是实现简单、安全性较高(依赖服务器存储),但在分布式系统中需要额外配置共享存储(如 Redis)。随着前后端分离和跨域场景增多,Token 机制逐渐成为主流,但 Session 仍在传统 Web 应用中广泛使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值