TGI 网关切换后端不同模型时,JWT 校验中间件应当放在网关入口,也就是路由动作之前。切换模型属于路由选择,鉴权是这个选择的前置条件。让中间件在网关注册一次,然后把解析后的用户上下文通过请求头透传给后端模型服务,后端不需要再验签。
JWT 中间件应置于网关入口,先鉴权后路由。切换模型不改变鉴权结果,只需把 JWT 解析出的用户标识、权限等上下文以请求头方式透传给后端。后端不重复验签,避免每个模型服务维护独立密钥。注意放行内部健康检查路径,并统一处理密钥轮换和过期时间。
为什么要在网关入口做统一鉴权
如果每个模型服务各自校验 JWT,切换模型时就需要给新接入的模型单独写一遍校验逻辑,密钥和规则也难以保持一致。把校验放在网关入口后,模型服务的职责只剩处理推理请求。网关本身可以是 Nginx、APISIX、Kong,也可以是一段自建的 Express 或 FastAPI 中间件,不改变现有 TGI 后端即可生效。
JWT 校验中间件需要完成的动作
以一个典型的请求为例:客户端携带 Authorization: Bearer Token 访问网关,网关先读 token,校验签名、过期时间、issuer、audience,然后提取用户身份(如 sub)和权限(如 roles)。校验通过后,把用户信息写入可识别的请求头,比如 x-user-id 和 x-user-roles,再交给后续路由逻辑。校验失败直接返回 401,不进入模型路由。
健康检查、部分公开接口需要排除在外,可以通过路径前缀或白名单数组实现。密钥轮换时建议用 JWKS 或支持多密钥验证的库,避免切换密钥瞬间大量请求失败。
模型切换时如何保持上下文透传
模型切换通常由请求中的 model 字段控制,或者按 URL 路径区分。无论哪种方式,都应当先执行鉴权中间件,再读取模型参数并转发。转发时保留之前写入的用户请求头,同时可以考虑把模型名也附加到头部,便于后端做租户隔离或计量。
// 以 Node.js + jsonwebtoken 为例,Express 风格中间件
const jwt = require('jsonwebtoken');
function authMiddleware(req, res, next) {
const header = req.headers.authorization || '';
const token = header.startsWith('Bearer ') ? header.slice(7) : null;
if (!token) {
return res.status(401).json({ error: 'missing token' });
}
try {
const claims = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'],
// audience: 'your-api',
// issuer: 'your-issuer'
});
// 将用户上下文透传给后端模型服务
req.headers['x-user-id'] = claims.sub;
req.headers['x-user-roles'] = JSON.stringify(claims.roles || []);
next();
} catch (e) {
return res.status(401).json({ error: 'invalid token' });
}
}
// 在模型路由上先过鉴权,再根据 model 字段选择 TGI 上游
app.post('/v1/chat/completions', authMiddleware, (req, res, next) => {
const model = req.body.model;
if (model === 'llama-3.1-8b') {
req.url = '/v1/chat/completions';
proxy.web(req, res, { target: 'http://tgi-a:8080' });
} else if (model === 'qwen2.5-7b') {
req.url = '/v1/chat/completions';
proxy.web(req, res, { target: 'http://tgi-b:8080' });
} else {
res.status(400).json({ error: 'unsupported model' });
}
});
这里的 proxy 可以是 http-proxy-middleware 或其他转发库。关键是 authMiddleware 只写一次,后续新增模型只需要改路由表,不需要动鉴权代码。如果不同模型对应不同权限,可以在 JWT 里放入权限列表,中间件再根据目标模型做二次判断,仍然在网关层完成。
验证清单
- 签发一个未过期的 JWT,分别指向两个不同模型,确认两个请求都能转发到对应 TGI 后端,且后端收到的请求头中包含 x-user-id。
- 使用过期 token 或篡改签名的 token 访问任意模型路径,确认返回的是 401 而不是后端 502。
- 将模型名从 llama-3.1-8b 切换到 qwen2.5-7b,不重新登录,直接用原 token 发起请求,确认鉴权结果不变。
- 检查健康检查路径(如 /health)是否被中间件放行,避免网关健康检查因缺少 token 而失败。
- 密钥轮换后,使用新旧两个 token 各请求一次,确认旧 token 在新密钥下失效,新 token 正常通过,且切换过程不会导致未签发的请求进入模型路由。