Files
datahub/docs/api_key_validate_flow.md
T
2026-04-17 11:06:34 +08:00

3.3 KiB
Raw Blame History

API Key 认证流程

概述

API Key 认证是系统支持的两种认证方式之一(另一种是 JWT)。客户端通过 X-API-Key 请求头传递明文 key,中间件负责解析、校验并将认证用户注入到 request attribute 中,供下游中间件和控制器使用。

API Key 格式

明文格式:{user_id}#{token}

  • user_id:用户 ID(整数)
  • #:分隔符
  • token64 字符十六进制随机串(bin2hex(random_bytes(32))

示例:42#a3b5c7d9e1f2...(完整 token 为 64 字符)

数据库仅存储 token 的 SHA-256 哈希值(key_hash),不存储明文。明文仅在生成时返回给用户一次。

认证流程图

flowchart TD
    A["请求进入 AuthMiddleware"] --> B{"有 Bearer Token?"}
    B -- 是 --> JWT["JWT 认证路径"]
    B -- 否 --> C{"有 X-API-Key 头?"}
    C -- 否 --> R401_NO["401 未授权,请先登录"]
    C -- 是 --> D["解析明文 key"]

    D --> E{"包含 # 分隔符?"}
    E -- 否 --> R401_FMT["401 API Key 无效或已过期"]
    E -- 是 --> F["拆分 user_id 和 token sha256(token) → key_hash"]

    F --> G["查询 api_keys 表WHERE (user_id, key_hash)AND 未过期"]
    G --> H{"记录存在?"}
    H -- 否 --> R401_KEY["401 API Key 无效或已过期"]
    H -- 是 --> I{"key.enabled?"}

    I -- false --> R403_KEY["403 该 API Key 已被禁用"]
    I -- true --> J["加载关联 user"]
    J --> K{"user 存在且user.status = 1?"}

    K -- 否 --> R403_USER["403 账号已被禁用"]
    K -- 是 --> L{"user.api_key_enabled?"}

    L -- false --> R403_FEAT["403 API Key 功能未启用"]
    L -- 是 --> M["认证成功"]

    M --> N["更新 last_used_at"]
    N --> O["注入 request attribute\nauth_user → User\nauth_type → 'api_key'"]
    O --> P["写入协程 Context"]
    P --> Q["放行到下游 handler"]

    style R401_NO fill:#fdd,stroke:#c00
    style R401_FMT fill:#fdd,stroke:#c00
    style R401_KEY fill:#fdd,stroke:#c00
    style R403_KEY fill:#fdd,stroke:#c00
    style R403_USER fill:#fdd,stroke:#c00
    style R403_FEAT fill:#fdd,stroke:#c00
    style M fill:#dfd,stroke:#0a0
    style JWT fill:#def,stroke:#08c

关键 SQL

解析阶段的数据库查询走 (user_id, key_hash) 联合索引,单次精确命中:

SELECT * FROM api_keys
WHERE user_id = {user_id}
  AND key_hash = {hash}
  AND (expires_at IS NULL OR expires_at > NOW())
LIMIT 1

数据查询汇总

整个认证流程涉及 2 次数据库查询 + 1 次写入:

操作 SQL 说明
查找 API Key SELECT FROM api_keys WHERE (user_id, key_hash) 联合索引精确匹配
加载关联用户 SELECT FROM users WHERE id = {user_id} $api_key->user 懒加载
更新使用时间 UPDATE api_keys SET last_used_at = NOW() 记录最后使用时间

下游消费

认证完成后,下游代码通过以下方式获取认证用户:

  • 中间件$request->getAttribute('auth_user') 或从 Context 读取
  • 控制器$this->getAuthUser()AbstractController 提供,含 JWT guard 兜底)

相关文件

文件 职责
app/Middleware/AuthMiddleware.php 认证入口,执行校验链
app/Model/ApiKey.php key 解析、DB 查询、格式定义
app/Controller/AbstractController.php getAuthUser() 统一用户获取