存数据库是唯一合理选择,因可动态禁用、轮换及分级权限;需建client关联表并哈希存储密钥,加唯一索引、长度校验与时效检查,禁用时仅设is_active=false并防缓存。

API密钥该存数据库还是配置文件
存数据库是唯一合理选择。硬编码在 .env 或 config/api.php 里等于把密钥和代码耦合,无法动态禁用、轮换或按客户端分级权限。
- 密钥必须关联到具体
client记录(哪怕只是个名字+状态字段) - 表结构至少含:
id、client_name、api_key(建议用hash_hmac('sha256', $raw, config('app.key'))存储,不存明文)、is_active、expires_at - 不要用
Str::random(32)直接当密钥返回——它没做防碰撞校验,得查库确认唯一性后再保存
Laravel自带的 Sanctum / Passport 能直接用吗
Sanctum 的 tokenable_type + tokenable_id 模型适合用户会话,不适合纯 API 客户端鉴权;Passport 过重,强制 OAuth2 流程,多数内部系统或 B2B 接口根本不需要授权码交换。
- 如果只是「请求头带
X-API-Key: abc123,后端查库放行」,自己写中间件更轻、更可控 - 别碰
Passport::tokensCan()—— 它绑定的是用户权限,不是客户端能力 - Sanctum 的
createToken()生成的是用户级 token,和客户端密钥语义不同,混用会导致审计混乱
怎么写一个安全又不拖慢的 API 密钥验证中间件
核心是避免每次请求都全表扫 api_keys。加索引、提前短路、拒绝无效格式。
- 必须给
api_key字段加唯一索引:ALTER TABLE api_keys ADD UNIQUE INDEX idx_api_key (api_key); - 中间件里先用
strlen($key) !== 40快速过滤掉明显非法值(比如 base64 编码的密钥可按长度预判) - 查库用
ApiKey::where('api_key', $key)->where('is_active', true)->first(),别用->firstOrFail()—— 失败是常态,要返回 401 而非 500 - 不要在中间件里加载关联模型(比如
->with('client')),真需要 client 信息,等鉴权通过后再查
密钥泄露后如何快速响应
没有“立即生效”的吊销机制,靠的是数据库字段 + 查询逻辑双保险。
- 所有验证逻辑必须检查
is_active和expires_at,且用whereRaw('expires_at > ?')避免 PHP 端时区偏差 - 禁用密钥只要更新
is_active = false,不用删记录——删了就失去操作留痕 - 日志里记下
request()->header('X-API-Key')的前 8 位(如abcd1234...)就够了,别存完整密钥 - 最容易被忽略的一点:Nginx 或 CDN 可能缓存了 401 响应,密钥禁用后前端仍可能拿到旧错误页——得在中间件响应头里加
Cache-Control: no-store
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











