1. “登录了,为什么不认识我?”(问题的开端)
OAuth2、JWT、会话认证… 认证方式实在太多了,大多数情况下已经足够。我也曾如此。
- 当在自己写的邮件客户端或 ChatGPT 的 MyGPT 中加入 OAuth2 时,感觉“这才是真正的用户体验”。
- 单纯的 Django 服务器的 Web 应用,会话认证 是最佳选择!
- 前后端分离的项目中,JWT 最为简洁。
然而,这些组合在某个时刻会一起崩塌。
关键点是 异步任务(Celery)。用户点击按钮时,后端并不是直接处理,而是把任务交给远程的 AI 计算服务器或 worker。此时 worker 会说:
“我收到了请求,但这是谁的请求?没有 request.user”。

2. 问题在于 “后端 ↔ 后端” + “异步 worker(Celery)”
我决定引入 API Key 的根本原因是 后端服务器之间的通信,而 Celery worker 介入其中的结构。
用户点击按钮后,请求并不会直接到达 AI 计算服务器,而是:
- 用户发送 Web 请求
- 后端把“任务”放入队列
- Celery worker 消费队列,并 向某个后端/计算服务器发起异步请求
在这种情况下,最痛的点是:
- worker 没有 request.user
- 没有会话(因为不是浏览器)
- JWT 也很尴尬(谁来管理、在哪里、如何传递 token)
- OAuth2 更是需要用户交互,根本不可用
当 JWT 和会话失效时,唯一剩下的问题被压缩为:
“计算服务器如何知道是哪个客户(租户/用户)在执行这项任务?”
3. 在 worker 世界里,先要“识别”再谈“认证”
在 Web 请求中,认证 = 登录,登录 = 用户,自然衔接。 但 worker 不是人,而是 自行借用 CPU 运行的应用程序,因此在它们之间,先要“识别”。认证可以通过服务器间的 HMAC 或 secretKey 解决。
- 任务必须使用 A 客户 的数据执行
- 结果必须保存到 A 客户 的资源中
- 计费/权限/配额也要基于 A 客户 扣除
如果硬要用 JWT 或会话去套,这会导致 token 的颁发、存储、传递、过期、刷新设计膨胀,而且会产生一种强烈的违和感:
“即使是我的服务器的客户,但用户并未在浏览器中操作,后端去为其获取 JWT?”
这种想法太不自然,我立刻放弃了。
4. 解决方案:API Key 在此环节既简单又强大
于是我采用了 API Key,它一次性解决了所有问题。
- worker 发起内部请求时,只需要 一个 Header 即可完成 认证+识别
- 服务器凭此 key 能立即 映射到具体的用户/客户
- Key 的回收/更换(轮转)也非常明确
示例请求如下:
POST /v1/ai/jobs
Authorization: Api-Key <KEY>
Content-Type: application/json
{ "job_id": "...", "payload": {...} }
即使 worker 没有 request.user,只要把上面的请求发出去,接收方后端即可通过文中说明的方式利用 API Key 确认用户身份。
5. 关键改进:把 API Key 与 USER 绑定后运维变得轻松
我特别满意的是这点:
常见的 rest_framework_api_key 库提供了基本的 Key 功能,但我的场景需要 “Key ↔ 用户(客户)绑定”。于是我继承 AbstractAPIKey,实现 CustomAPIKey,并通过 FK 关联到 AUTH_USER 模型。
效果令人惊喜。
from django.conf import settings
from rest_framework_api_key.models import AbstractAPIKey
from django.db import models
class CustomAPIKey(AbstractAPIKey):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="api_keys"
)
is_test = models.BooleanField(default=False) # 区分阶段/测试 Key
这样一来,除了普通的 认证,还能打开一系列 运维功能。
6. 为每个用户自动发放 Key 带来的运维收益
在用户注册时自动为其创建一个 Key,运营上获得了以下便利:
1) 便于管理有效性
- 查询/禁用/删除某用户的 Key 非常简单
- 用户注销时,关联的 Key 会随之级联删除
2) Key 轮转更容易
- 遇到“Key 泄漏”时,直接生成新 Key 并废除旧 Key,流程清晰
- 支持多 Key,可实现 无缝切换(新 Key 部署后再废除旧 Key)
3) 计费/配额/权限可以以用户为单位
- 不再是基于单个 Key,而是 基于用户 进行计费和限制
- 不需要每次都去推断 “这个 API Key 属于谁”
4) 单个用户可拥有多个 Key
is_test 之类的标记在这里发挥作用。因为 API Key 通过 FK 关联,而不是 OneToOne,单个用户可以拥有多把钥匙用于不同场景。
- 同一用户可以同时拥有 测试环境 Key 与 生产环境 Key
- 开发/运维流程可以清晰分离
- 在日志/监控中也能轻松区分 “测试流量” 与 “真实流量”
7. 认证方式不是优劣之分,而是“情境武器选择”
总结我目前的最佳组合如下:
- OAuth2:适用于外部服务/客户端集成、需要用户授权的场景
- 会话认证:单体 Django Web 应用,开发速度快、实现最简
- JWT:前后端分离、移动端/SPA 等多客户端场景的平衡方案
- API Key:后端‑后端、自动化/worker/批处理等 非用户请求 场景的首选
尤其在 Celery worker 介入时,试图用 登录认证 统一整个体系只会增加复杂度。此时 API Key 成为最干净的出路。
8. 结语
人(浏览器/App)自然使用会话/JWT/OAuth2 来处理。 但 worker 不是人,而是进程,必须能够 识别出它代表的是哪个用户的工作。
我转向 API Key 并不是因为宏大的安全论证,而是因为它在那个环节最简洁地解决了问题。把 Key 与 USER 绑定后,Key 管理不再是工具,而是 运维杠杆。
大家在项目中也经常使用 API‑Key 吗?我分享的方式只是 API‑Key 便利性的一个切面,希望能为阅读此文的你带来一点灵感。
相关链接