Skip to content

051. 密码工具、JWT 编解码与用户模型

学习目标

这一节实现认证系统的核心工具和用户模型。

学完后,你应该能理解:

  • 为什么认证相关代码集中放到 auth 模块;
  • 密码工具需要哪些方法;
  • JWT token 为什么要区分编码和解码;
  • token payload 里通常放什么;
  • 用户模型为什么要区分私有模型和公开结构;
  • 登录认证函数要检查哪些条件。

认证模块

用户认证属于后端核心能力。

可以在应用目录里创建独立的 auth 文件或模块,把认证相关工具集中放进去。

这样后续注册、登录、刷新 token、权限校验都能复用同一套逻辑。

密码工具

密码工具负责处理明文密码和密文密码。

它至少需要两个能力:

  • 把明文密码哈希成密文;
  • 验证明文密码和密文密码是否匹配。

工具初始化时会读取签名密钥和算法配置。

这样项目里其他地方不需要重复关心底层加密细节。

密码哈希测试

测试密码哈希时,不应该断言密文等于某个固定字符串。

因为同一个密码每次生成的密文可能不同。

更合理的测试是:

  • 哈希后的值不等于明文;
  • 正确密码可以通过验证;
  • 错误密码不能通过验证。

这样测试的是行为,而不是某一次运行的随机结果。

JWT 编码

JWT 编码就是把字典对象转成 token 字符串。

payload 里可以放:

  • 用户名;
  • token 类型;
  • 过期时间;
  • 其他需要随 token 携带的轻量信息。

过期时间通常写入 exp 字段。

解码时,如果当前时间超过 exp,token 会被视为过期。

token 类型

同一个系统里会有多种 token。

例如:

  • access: 用来访问接口;
  • refresh: 用来刷新登录状态;
  • active: 用来激活账号。

把类型写进 payload 后,后端就能判断这个 token 应该用于哪个场景。

激活账号的 token 不应该拿来访问普通业务接口。

JWT 解码

JWT 解码会把 token 字符串还原成 payload。

解码失败可能有多种原因:

  • token 已过期;
  • token 被篡改;
  • token 格式错误;
  • 签名密钥不匹配;
  • 算法不匹配。

工具函数可以统一处理这些异常。

无法解码时返回空值或抛出业务异常,再由上层决定如何响应。

并发生成 token

测试里还会验证并发生成 token 的情况。

同时生成多个 token 时,数量应该正确,结果也应该保持可用。

这类测试可以帮助你确认工具函数在多次调用下没有共享状态污染。

用户状态枚举

用户表里会有状态字段。

例如:

  • 未激活;
  • 正常;
  • 禁用。

用枚举约束状态值,比到处写字符串更清晰。

它也能减少拼写错误带来的问题。

私有模型和公开结构

用户表里的字段不都能返回给前端。

例如哈希密码只能后端内部使用。

所以需要区分:

  • 后端内部使用的用户模型;
  • 可以返回给前端的公开用户结构;
  • 注册时接收参数的结构。

公开结构里不应该包含哈希密码。

这是接口设计里的安全边界。

登录认证函数

登录认证函数接收用户名、密码和数据库 session。

它通常会做这些检查:

  • 用户是否存在;
  • 用户是否已激活;
  • 用户是否被禁用;
  • 密码是否正确。

任一步失败,都应该返回认证失败。

全部通过后,才返回公开用户信息。

本地跳过密码校验

项目里可能会有一个配置项,用来控制是否验证密码。

它适合本地初始化或忘记管理员密码时临时使用。

这个开关很危险。

线上环境不应该关闭密码校验。

这一节的重点

这一节把认证的底层积木搭起来。

你需要记住:

  • 密码工具只暴露哈希和验证能力;
  • JWT payload 要写清 token 类型和过期时间;
  • 解码失败要统一处理;
  • 用户公开结构不能包含敏感字段;
  • 登录前必须检查用户状态和密码。

AI Agent 课程学习文档。