用户认证

设计目标

我决定实现用户认证系统,让每个用户有独立的调用配额。

核心需求:

  1. 用户可以注册账号
  2. 系统分配唯一的 API Key
  3. 每次调用必须验证 API Key
  4. 限制每个用户的调用配额

这是一个完整的认证体系,我需要从零开始设计。

方案设计

API Key(访问密钥)的设计

API Key 是什么?

  • 一个唯一的字符串
  • 也可以理解为用户调用 API 时携带的访问密钥
  • 用来标识用户身份和调用权限
  • 需要在每次调用时携带

API Key 的格式:

ak_live_xxxxxxxxxxxxxxx  (正式环境)
ak_test_xxxxxxxxxxxxxxx  (测试环境)

格式说明:

  • ak_:前缀,表示 API Key
  • live/test:环境标识
  • 后面:随机字符串

我特意加了环境标识,这样开发和生产环境可以分开管理。

数据模型设计

API Key 生成

生成安全的 API Key

设计流程
生成安全的 API Key
  1. 步骤 1:校验调用方身份,并绑定用户、应用和权限范围
  2. 步骤 2:校验身份、密钥或权限
  3. 步骤 3:读取 API Key、调用方信息和请求上下文
  4. 步骤 4:根据认证结果、权限和配额决定放行或拒绝
关注点:身份可信度、权限边界、配额消耗和审计追踪。

为什么使用 secrets 模块?

  • 加密安全的随机数生成
  • 不可预测
  • 防止碰撞

我当时想,API Key 是用户的身份标识,必须在源头上保证安全。

用户注册流程

注册接口

设计流程
注册接口
  1. 步骤 1:生成认证结果并绑定用户、应用和权限范围
  2. 步骤 2:写入队列并异步消费
  3. 步骤 3:校验身份、密钥或权限
关注点:身份可信度、权限边界、配额消耗和审计追踪。

登录接口

设计流程
登录接口
  1. 步骤 1:生成认证结果并绑定用户、应用和权限范围
  2. 步骤 2:写入队列并异步消费
  3. 步骤 3:校验身份、密钥或权限
关注点:身份可信度、权限边界、配额消耗和审计追踪。

我特意让 API Key 只在注册时返回一次,之后就再也看不到了。这样设计是为了安全,但也带来了一些麻烦——用户如果弄丢了 API Key,就只能重置。

API 调用认证

修改天气 API 接口

设计流程
修改天气 API 接口
  1. 步骤 1:校验调用方身份,并绑定用户、应用和权限范围
  2. 步骤 2:生成认证结果并绑定用户、应用和权限范围
  3. 步骤 3:校验调用方身份,并绑定用户、应用和权限范围
  4. 步骤 4:计算用量、账单或套餐状态
关注点:身份可信度、权限边界、配额消耗和审计追踪。

通过统一认证入口,我可以把认证逻辑从业务流程中分离出来。这是我从之前做系统设计的经验中学到的——关注点分离。

客户端使用方式

正确的调用方式

设计流程
正确的调用方式
  1. 步骤 1:校验身份、密钥或权限
  2. 步骤 2:读取 API Key、调用方信息和请求上下文
  3. 步骤 3:根据认证结果、权限和配额决定放行或拒绝
  4. 步骤 4:返回认证结果,并写入审计、配额和异常访问记录
关注点:身份可信度、权限边界、配额消耗和审计追踪。

错误的调用方式

设计流程
错误的调用方式
  1. 步骤 1:校验身份、密钥或权限
  2. 步骤 2:读取 API Key、调用方信息和请求上下文
  3. 步骤 3:根据认证结果、权限和配额决定放行或拒绝
  4. 步骤 4:返回认证结果,并写入审计、配额和异常访问记录
关注点:身份可信度、权限边界、配额消耗和审计追踪。

安全考虑

API Key 的安全问题

问题 1:API Key 泄露

  • 如果 API Key 泄露,他人可以冒用
  • 配额被消耗
  • 产生费用

解决方案:

  1. 提醒用户妥善保管 API Key
  2. 提供重置 API Key 的功能
  3. 设置 IP 白名单(可选)
  4. 监控异常调用

密码存储

问题 2:密码不能明文存储

设计流程
密码存储
  1. 步骤 1:读取 API Key、调用方信息和请求上下文
  2. 步骤 2:根据认证结果、权限和配额决定放行或拒绝
  3. 步骤 3:返回认证结果,并写入审计、配额和异常访问记录
关注点:身份可信度、权限边界、配额消耗和审计追踪。

更好的方案是使用 bcrypt

设计流程
密码存储
  1. 步骤 1:读取 API Key、调用方信息和请求上下文
  2. 步骤 2:根据认证结果、权限和配额决定放行或拒绝
  3. 步骤 3:返回认证结果,并写入审计、配额和异常访问记录
关注点:身份可信度、权限边界、配额消耗和审计追踪。

我当时想,安全这件事,再怎么重视也不为过。

真实上线还要注意
  • 不要只验证“这个 Key 对不对”。 还要记录它是谁、什么时候、从哪里调用了什么接口。
  • Key 泄露要能止损。 用户应该能重置密钥,系统也应该能临时停用异常密钥。
  • 认证、限流、计费要串起来。 否则用户明明被限流了,账单和日志却说不清原因。

效果验证

上线后,我观察了一周的数据:

滥用情况

指标之前现在
异常 IP 调用每天 10+ 个0 个 ✅
外部 API 滥用频繁0 次 ✅
正常用户体验优秀 ✅

用户增长

指标数值
注册用户200 个
日活用户80 个
平均每用户调用100 次/天

看到这些数据,我知道这条路走对了。

新的问题

虽然解决了滥用问题,但带来了一些新挑战:

问题 1:数据存储

用户数据和调用日志越来越多:

  • 用户表:200 条
  • 日志表:每天 5 万条
  • 增长速度:每月 150 万条

应该用什么数据库?

问题 2:查询性能

日志表查询越来越慢:

设计流程
问题 2:查询性能
  1. 步骤 1:读取 API Key、调用方信息和请求上下文
  2. 步骤 2:根据认证结果、权限和配额决定放行或拒绝
  3. 步骤 3:返回认证结果,并写入审计、配额和异常访问记录
关注点:身份可信度、权限边界、配额消耗和审计追踪。

随着数据量增长,这个查询会越来越慢。

如何优化?

问题 3:数据备份

如果数据库挂了,所有用户数据都会丢失。

如何备份数据?

一个问题解决了,新的问题又来了。这就是做系统的常态吧。

当前架构