api密钥需通过密码学安全随机生成(如random_bytes(32)),而非加密算法;必须原样存储、https传输,并配合唯一索引、bearer头校验及严格访问控制。

api_key 不是靠“加密”生成的,而是靠安全随机生成 + 唯一性保障 + 安全存储实现的。ThinkPHP6 本身不提供 generateApiKey() 这类内置方法,你得自己写逻辑,且不能用 md5(time().rand()) 这类弱方式。
如何生成真正可用的 api_key
- 必须使用密码学安全的随机源:
random_bytes(32)或bin2hex(random_bytes(32)),不能用uniqid()、mt_rand()、time() - 推荐长度:至少 32 字节(64 字符 hex)或 Base64 编码后约 44 字符,确保熵值足够
- 生成后必须立即存入数据库,并加唯一索引(
UNIQUE KEY <code>uniq_api_key(api_key)),防止重复 - 若插入失败(主键/唯一键冲突),需重试生成,不能直接返回错误给前端
- 不要对
api_key做任何哈希或加密存储——它要原样比对,不是密码;但必须 HTTPS 传输、服务端严格校验来源 IP/Referer(可选)
示例代码片段:
$key = bin2hex(random_bytes(32));
while (Db::name('user')->where('api_key', $key)->find()) {
$key = bin2hex(random_bytes(32));
}
Db::name('user')->where('id', $uid)->update(['api_key' => $key]);
为什么不能用 md5()、sha1() 或其他哈希生成 api_key
- 哈希是确定性函数,输入可控就可能被穷举或预测(比如
md5('user123'.time())) -
api_key是访问凭证,不是密码;它一旦泄露等于账号裸奔,所以必须“不可预测+高熵” - 如果你把它当密码一样
password_hash($key, PASSWORD_ARGON2ID)存储,那验证时就无法反查——API 请求头里的Authorization: Bearer xxx拿到的是明文,你得原样比对,不是校验哈希
ThinkPHP6 中校验 api_key 的常见错误
- 直接用
$request->header('Authorization')取值,但没 trim() 或没拆解Bearer xxx前缀,导致比对失败 - 从数据库查
api_key时没加索引,QPS 上去后慢成瓶颈 - 在中间件里校验时,忘了
return提前终止,后续逻辑仍执行(比如写了日志但没拦住非法请求) - 把
api_key放 query 参数里传(如?key=xxx),既易泄露又进 access log,应强制走Authorization: Bearer xxx头
校验建议写法:
$header = $request->header('authorization', '');
if (strpos($header, 'Bearer ') !== 0) {
throw new HttpException(401, 'Invalid Authorization header');
}
$api_key = trim(substr($header, 7));
$user = Db::name('user')->where('api_key', $api_key)->find();
if (!$user) {
throw new HttpException(401, 'Invalid API key');
}
关键点其实就一个:api_key 是身份令牌,不是密文,它的安全性只来自随机性和传输/存储环节的防护,跟“加密算法”无关。很多人卡在“怎么加密生成”,其实是方向错了。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











