一、认证与授权基础

1.1 什么是认证?说白了就是「你是谁」

认证,英文叫 Authentication。我习惯把它理解为「验明正身」的过程。

你登录网站时输入用户名和密码,系统去数据库里比对一下——嗯,对得上,你就是你。这就是认证。

举个例子:你拿着身份证过高铁闸机,刷脸通过。机器确认「这张脸和身份证上是同一个人」——这就是认证。

在 Web 世界里,常见的认证方式有:

  • 密码认证:最传统,用户名+密码
  • 短信/邮箱验证码:一次性临时凭证
  • 生物特征:指纹、人脸识别
  • OAuth 第三方登录:用微信、GitHub 账号登录
我的经验: 千万别把密码明文存数据库。我曾经接手过一个项目,用户表里 password 字段存的居然是明文……吓得我连夜加了 bcrypt 哈希。你想想看,要是数据库被拖库,那画面太美不敢看。

1.2 什么是授权?说白了就是「你能干什么」

认证和授权,这两个词经常被搞混。我面试时也常问这个问题。

认证是确认身份,授权是确认权限。

举个生活中的例子:你走进公司大门,刷工牌——这是认证。但你能进财务室吗?能进机房吗?这取决于你的工牌权限——这就是授权。

在系统里,授权通常表现为:

  • 普通用户只能看自己的订单
  • 管理员可以删除任何人的订单
  • 超级管理员可以修改系统配置

常见的授权模型有:

模型 说明 适用场景
ACL(访问控制列表) 每个资源绑定一个权限列表 小系统、文件系统
RBAC(基于角色的访问控制) 用户 -> 角色 -> 权限 企业系统、后台管理
ABAC(基于属性的访问控制) 根据用户、资源、环境等属性动态判断 大型复杂系统
注意: 认证通过不代表授权通过。我见过不少新手在写接口时,只检查了「是否登录」,却没检查「是否有权限」。结果普通用户能调管理员接口……这属于严重的安全漏洞。

1.3 Cookie 与 Session 机制详解

这是 Web 认证的「老前辈」了。虽然现在 Token 很流行,但 Cookie + Session 依然在很多传统项目里服役。

1.3.1 什么是 Cookie?

Cookie 是浏览器存储在本地的小型文本文件。每次请求时,浏览器会自动把 Cookie 带上。

特点:

  • 大小限制:一般 4KB 左右
  • 可设置过期时间
  • 可以设置 HttpOnly(禁止 JS 读取)
  • 可以设置 Secure(仅 HTTPS 传输)

1.3.2 什么是 Session?

Session 是服务器端存储的用户会话数据。服务器生成一个唯一的 Session ID,通过 Cookie 发给浏览器。

工作流程:

  1. 用户登录 -> 服务器创建 Session,生成 Session ID
  2. 服务器把 Session ID 写入 Cookie,返回给浏览器
  3. 浏览器后续请求自动带上这个 Cookie
  4. 服务器根据 Session ID 查找对应的 Session 数据
// Node.js 中使用 express-session 的示例
const session = require('express-session');

app.use(session({
  secret: 'my-secret-key',     // 用于签名 Session ID
  resave: false,               // 是否每次请求都重新保存
  saveUninitialized: false,    // 是否保存未初始化的 Session
  cookie: {
    httpOnly: true,            // 禁止 JS 读取
    secure: true,              // 仅 HTTPS
    maxAge: 24 * 60 * 60 * 1000 // 过期时间:1天
  }
}));

// 登录成功后
app.post('/login', (req, res) => {
  // 验证用户名密码...
  req.session.userId = user.id;
  req.session.role = user.role;
  res.send('登录成功');
});

// 后续请求中
app.get('/profile', (req, res) => {
  if (!req.session.userId) {
    return res.status(401).send('请先登录');
  }
  // 正常处理...
});
核心要点: Session 数据存在服务器,浏览器只存一个 ID。所以 Session 方案天然是「有状态」的——服务器得记住每个用户的状态。

1.3.3 Cookie + Session 的优缺点

优点 缺点
实现简单,成熟稳定 服务器需要存储 Session,占用内存
可以主动销毁 Session(强制下线) 分布式环境下需要共享 Session(Redis)
Cookie 可设置 HttpOnly,相对安全 存在 CSRF 攻击风险
浏览器自动管理,开发者省心 移动端 App 不天然支持 Cookie
避坑指南: 我曾经在一个分布式项目里踩过 Session 共享的坑。A 服务器登录了,请求打到 B 服务器,Session 找不到……后来用 Redis 做集中存储才解决。如果你用 Node.js,推荐用 connect-redis 来存 Session。

1.4 Token 认证模式介绍

Token 认证,说白了就是「我给你一个令牌,你拿着它来证明身份」。

和 Session 不同,Token 是无状态的。服务器不存 Token,只负责验证 Token 的合法性。

1.4.1 Token 的工作流程

  1. 用户登录 -> 服务器验证身份 -> 生成 Token 返回
  2. 客户端保存 Token(localStorage / 内存 / Cookie)
  3. 每次请求时,在 HTTP Header 里带上 Token
  4. 服务器验证 Token 签名 -> 解析出用户信息
// Token 认证的典型流程(伪代码)
// 登录接口
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  // 验证用户名密码...
  const user = { id: 123, role: 'admin' };
  
  // 生成 Token
  const token = jwt.sign(
    { userId: user.id, role: user.role },
    'secret-key',
    { expiresIn: '7d' }
  );
  
  res.json({ token });
});

// 受保护接口
app.get('/profile', (req, res) => {
  // 从 Header 中获取 Token
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) {
    return res.status(401).send('Token 缺失');
  }
  
  try {
    // 验证 Token
    const decoded = jwt.verify(token, 'secret-key');
    req.user = decoded;
    // 正常处理...
  } catch (err) {
    return res.status(401).send('Token 无效或已过期');
  }
});

1.4.2 Token 和 Session 的核心区别

对比项 Session Token
状态 有状态(服务器存数据) 无状态(服务器不存数据)
存储位置 服务器内存 / Redis 客户端(浏览器 / App)
扩展性 需要共享 Session 天然支持分布式
跨域 受限于 Cookie 同源策略 可以跨域使用
主动失效 可以(删除 Session) 较麻烦(需要黑名单)
移动端支持 不友好 天然支持
我的建议: 如果你做的是传统 Web 应用,用户量不大,用 Session 完全够用。如果你做的是前后端分离、移动端 App、或者微服务架构,Token 是更好的选择。我个人现在新项目基本都用 Token,省心。

1.4.3 Token 的常见类型

  • JWT(JSON Web Token):最流行,自包含用户信息,可签名可加密
  • Opaque Token:不透明 Token,就是一个随机字符串,需要查数据库才知道是谁
  • Bearer Token:一种使用方式,放在 Authorization: Bearer <token> 中
注意: JWT 虽然方便,但有个坑——签发后无法主动失效。我曾经遇到一个场景:用户修改密码后,旧的 JWT 依然有效,直到过期。解决方案是维护一个 Token 黑名单,或者用短过期时间 + 刷新 Token 机制。这个我们后面章节会详细讲。

小结

这一章我们聊了:

  • 认证是「你是谁」,授权是「你能干什么」
  • Cookie + Session 是有状态的经典方案
  • Token 是无状态的现代方案,适合分布式和移动端

下一章我们会深入 JWT 的细节——它的结构、签名算法、以及如何在实际项目中安全使用。嗯,到时候我会分享一些我踩过的坑,保证让你少走弯路。