3. API Key鉴权机制:API Key的概念、vLLM原生API Key支持、生成与管理API Key、在请求中传递API Key

说到API Key鉴权,这其实是我在部署vLLM服务时最先考虑的问题之一。你想想看,一个大模型服务暴露在公网上,如果没有鉴权机制,那简直就是开门揖盗。我早期有个项目就因为偷懒没加鉴权,结果被爬虫薅走了几百万次调用,账单直接爆了。从那以后,我对API Key的重视程度就拉满了。

3.1 API Key的概念

API Key说白了就是一个身份令牌。它是一串随机生成的字符串,用来标识调用方的身份。每次请求时,客户端把这个Key塞进请求头里,服务端收到后一比对,就知道你是谁、有没有权限调用。

我个人习惯把API Key类比成小区门禁卡。门禁卡本身不存你的个人信息,但它能证明你是业主。同样,API Key不关心你是谁,它只关心你有没有被授权。嗯,这里要注意一点:API Key不是密码,它不需要定期更换,但一旦泄露就必须立即吊销。

核心要点:API Key是一种轻量级的鉴权方式,适用于机器对机器的通信场景。它不依赖用户会话,也不存储敏感信息,只做身份校验。

3.2 vLLM原生API Key支持

vLLM其实内置了一套简单的API Key鉴权机制。我记得第一次翻源码时还觉得挺惊喜——它不需要额外装插件,开箱即用。

vLLM的鉴权逻辑是这样的:启动服务时通过环境变量或命令行参数传入一个或多个API Key,服务启动后,所有请求都必须携带有效的Key才能通过。如果Key不对,直接返回401 Unauthorized。

具体怎么启用呢?有两种方式:

  • 环境变量方式:设置 VLLM_API_KEY 环境变量
  • 命令行方式:启动时加 --api-key 参数

举个例子:

# 方式一:环境变量
export VLLM_API_KEY="sk-abc123def456"
python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-2-7b-chat-hf

# 方式二:命令行参数
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-2-7b-chat-hf \
    --api-key "sk-abc123def456"

这里有个坑,我曾经踩过:如果你同时设置了环境变量和命令行参数,vLLM会优先使用命令行参数的值。所以排查问题时,记得先确认到底用的是哪个。

注意:vLLM原生的API Key鉴权只支持单Key模式。如果你需要多用户、多权限级别的鉴权,就得自己在外层加一层网关或者反向代理了。

3.3 生成与管理API Key

API Key的生成其实不复杂,但管理起来学问不小。我一般用Python的 secrets 模块来生成,因为它比 random 更安全,适合做密码学相关的操作。

生成示例:

import secrets

def generate_api_key(prefix="sk-", length=32):
    """生成一个安全的API Key"""
    random_part = secrets.token_hex(length // 2)
    return f"{prefix}{random_part}"

# 生成一个Key
api_key = generate_api_key()
print(api_key)  # 输出类似:sk-1a2b3c4d5e6f7g8h9i0j...

管理方面,我建议至少做到这几点:

  • 存储加密:API Key绝对不能明文存数据库。用bcrypt或SHA-256加盐哈希后再存。我见过有人直接存明文,结果数据库一泄露,所有Key全废了。
  • 支持吊销:每个Key都要有状态字段,比如 activerevoked。一旦发现异常,立即吊销。
  • 设置过期时间:给Key加个 expires_at 字段,定期轮换。我个人习惯是90天强制过期。
  • 绑定IP或来源:如果调用方是固定服务器,可以把IP绑定到Key上,增加一层防护。

我曾经接手过一个项目,里面存了200多个API Key,全是永久有效的,而且没有任何使用记录。你想想看,这要是哪个Key泄露了,根本不知道是谁干的。后来我花了一周时间,把所有Key全部吊销,重新生成并分配,顺便加上了审计日志。

3.4 在请求中传递API Key

传递API Key的方式主要有三种,我按推荐程度排个序:

方式 说明 推荐度
HTTP Header 放在 Authorization: Bearer <key> ⭐⭐⭐⭐⭐
Query Parameter 拼在URL后面,如 ?api_key=xxx ⭐⭐
Request Body 放在JSON请求体里

最推荐的方式是用HTTP Header。为什么呢?因为Query Parameter会被记录在服务器日志里,容易泄露;Request Body则破坏了请求结构的统一性。Header既安全又规范,OpenAI也是这么做的。

用Python的 requests 库调用vLLM服务时,可以这样传Key:

import requests

url = "http://localhost:8000/v1/completions"
api_key = "sk-abc123def456"

headers = {
    "Authorization": f"Bearer {api_key}",
    "Content-Type": "application/json"
}

data = {
    "model": "meta-llama/Llama-2-7b-chat-hf",
    "prompt": "Hello, how are you?",
    "max_tokens": 50
}

response = requests.post(url, headers=headers, json=data)
print(response.json())

如果你用curl测试,命令是这样的:

curl http://localhost:8000/v1/completions \
  -H "Authorization: Bearer sk-abc123def456" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "meta-llama/Llama-2-7b-chat-hf",
    "prompt": "Hello, how are you?",
    "max_tokens": 50
  }'

小技巧:如果你用vLLM的OpenAI兼容接口,客户端可以直接用OpenAI的Python SDK,只需要改一下 api_keybase_url 就行。代码几乎不用改,非常方便。

最后说一个我踩过的坑:有一次我把API Key写死在代码里,结果不小心提交到了Git仓库。虽然马上删了,但Git历史里还留着。后来我用了 git filter-branch 才彻底清除。所以,API Key一定要从环境变量或配置中心读取,千万别硬编码。

API Key鉴权流程 客户端 请求 + API Key vLLM服务 鉴权模块 验证通过 模型推理 返回推理结果 验证失败 → 401 Key存储(哈希) 比对哈希值

这张图展示了整个鉴权流程。客户端发起请求时带上API Key,vLLM的鉴权模块先比对Key是否有效。如果通过,就继续走模型推理;如果失败,直接返回401。Key本身是哈希存储的,服务端不保存明文。

专注资料整理