apisix~forward-auth外部认证
针对你这个"使用外部鉴权接口 http://user.service/check 来校验请求头 Authorization" 的需求,最匹配的插件是 forward-auth。
推荐方案:forward-auth 插件
forward-auth 插件实现的就是"经典外部认证"模型。它会将客户端的请求转发给你指定的外部鉴权服务,然后根据该服务的响应来决定是否放行请求,非常适合你已经有独立鉴权服务的场景。
它的工作流程和配置要点如下:
- 转发请求:当请求到达配置了该插件的路由时,APISIX 会阻塞原始请求,并向你的鉴权服务
http://user.service/check发起一个 HTTP 调用。 - 携带凭证:通过配置
request_headers属性,你可以明确指定将客户端的Authorization请求头转发给鉴权服务。 - 决定放行:
- 鉴权通过:如果你的
check服务返回 2xx 状态码,APISIX 会认为请求合法,并将原始请求继续转发给上游后端服务。 - 鉴权失败:如果
check服务返回 非 2xx 状态码(如 401/403),APISIX 会拦截请求,并直接将鉴权服务的错误响应(或配置后的自定义信息)返回给客户端,不会将请求转发到上游。
- 鉴权通过:如果你的
核心配置示例
你可以通过 Admin API 或 Dashboard 在路由上启用该插件,一个核心配置示例如下:
{
"plugins": {
"forward-auth": {
"uri": "http://your-cas.com/internal/aut",
"request_headers": ["X-API-Key","Connection"], // 转到认证服务时,带上Authorization请求头
"request_method": "POST" // 后台为post方法
}
},
"upstream": {
"nodes": {
"your_real_upstream_host:port": 1
}
}
}
其他备选方案简述
除了 forward-auth,APISIX 还有其他相关插件,但它们并非你的场景下的最优解:
openid-connect:如果check接口遵循标准的 OIDC 协议,这个插件是更合适的选择,它支持自省等标准流程。但如果check接口是自定义协议,使用forward-auth灵活性更高。basic-auth/key-auth:这类插件是 APISIX 内置的认证方案,需要将用户凭证(用户名/密码或 Key)预先配置在 APISIX 的Consumer对象中,由 APISIX 自己完成校验,而不是转发给外部服务。
如果你想进一步确认 forward-auth 的配置细节,比如如何将鉴权服务返回的特定头信息(如 X-User-ID)传递给上游服务,我可以再为你展开说明。
将请求头内容改个名传递到上游
- 客户端 → APISIX:使用 Authorization: Bearer xxx
- APISIX → B服务(鉴权):转换成 X-API-Key: xxx(去掉 Bearer 前缀)
- plugins插件配置如下,它会把请求头中authorization中的token获取,然后到认证服务your-cas.com中请求头x-api-key进行认证,认证成功再转到上游服务
{
"forward-auth": {
"_meta": {
"disable": false
},
"request_headers": [
"X-API-Key",
"Connection"
],
"uri": "http://your-cas.com/internal/auth",
"request_method": "POST"
},
"proxy-rewrite": {
"regex_uri": [
"^/mcp-law-agg(/.*)",
"/mcp/router$1"
]
},
"response-rewrite": {
"_meta": {
"disable": false
},
"headers": {
"set": {
"X-DashScope-Request-ID": "$http_x_dashscope_request_id"
}
}
},
"serverless-pre-function": {
"_meta": {
"disable": false
},
"functions": [
"return function(conf, ctx) \n local auth_header = ngx.var.http_authorization; \n ngx.log(ngx.ERR, '=== DEBUG: auth_header = ', auth_header or 'nil'); \n if auth_header then \n local _, _, token = string.find(auth_header, '^%s*[Bb]earer%s+(.+)$'); \n if token then \n ngx.req.set_header('X-API-Key', token);ngx.req.set_header('Connection', 'close'); \n ngx.log(ngx.ERR, '=== DEBUG: X-API-Key set to ', token); \n else \n ngx.log(ngx.ERR, '=== DEBUG: Failed to extract token from: ', auth_header); \n end \n else \n ngx.log(ngx.ERR, '=== DEBUG: No Authorization header'); \n end \nend"
],
"phase": "rewrite"
}
}
浙公网安备 33010602011771号