使用nginx解决k8s traefik中basic auth的跨域问题:TaoToken统一Key接入下的配置骨架与验证

📅 发布时间:2026/9/30 18:35:12
使用nginx解决k8s traefik中basic auth的跨域问题:TaoToken统一Key接入下的配置骨架与验证
1. 为什么 traefik 的 basic auth 一开浏览器预检就挂先把问题场景说清楚。你在 k8s 里用 traefik 做 ingress某个域名挂上了 basic auth 中间件本来访问没问题。但一旦这个域名要被另一个 web 域比如前端页面、另一个后台系统用 fetch 或 axios 调用浏览器就会先发一个 OPTIONS 预检请求。这时候你会发现预检直接 401控制台报Response to preflight request doesnt pass access control check请求根本没走到你的业务服务。根因不复杂。basic auth 的认证信息是放在Authorization头里的而浏览器在跨域预检阶段默认不会把Authorization带上去它只想知道「这个跨域请求允不允许」。traefik 的 basic auth 中间件是在路由层做拦截的OPTIONS 请求同样会被它拦下来要求认证于是预检拿不到 2xx跨域直接失败。traefik 官方文档里关于 k8s 场景下 basic auth 与 CORS 预检怎么共存确实没有一份能直接抄的说明这也是很多人卡住的地方。我试过的思路是把 basic auth 从 traefik 层挪到 nginx 层让 nginx 在同一个 server 块里先处理 OPTIONS 预检直接返回 200 并带上 CORS 头再对真正的业务请求做 basic auth 校验。这样预检不碰认证正式请求才校验跨域和鉴权两不误。整体链路变成浏览器 → traefik ingress → nginx service → 后端业务 service。这个方案适合谁适合已经在 k8s 里跑 traefik、又需要给某个域名加 basic auth、同时该域名要被其他域跨域调用的同学。如果你还在纠结「为什么 traefik 里配了 CORS 头还是不行」那大概率就是预检被 basic auth 拦了往下看配置骨架。顺带说一句 AI 工具侧的接入。很多团队现在会把内部 AI 网关、模型调用通道也放在类似的 k8s 域名后面用统一 Key 管理。TaoToken 提供的就是这种统一 Key/API 通道官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口 https://taotoken.net/api 。当你的 AI 工具比如 Cline、Claude Code 这类需要跨域访问一个带 basic auth 的网关时同样会遇到预检问题所以这套 nginx 骨架对 AI 工具接入场景一样适用。下面先把前置准备讲清楚。2. TaoToken 统一 Key 接入前的环境与凭据准备在动手改 nginx 之前先把两件事准备好basic auth 的密码文件以及 TaoToken 侧的 Key 和 Base URL。这两块是后面所有配置的输入。2.1 生成 basic auth 密码文件用htpasswd生成命令很直接htpasswd -bc ngauth username password-b表示在命令行里直接传密码-c表示创建新文件。执行完会得到一个ngauth文件内容形如username:$apr1$xxxx$yyyy。这个文件后面要作为 ConfigMap 的一个 key 挂进 nginx 容器。注意ngauth里的用户名密码要和你实际使用的保持一致别生成完就忘了。如果你机器上没有htpasswdDebian/Ubuntu 系装apache2-utilsCentOS 系装httpd-tools即可。2.2 TaoToken 侧的 Key 与 Base URLTaoToken 的统一 Key 在控制台创建入口是 https://taotoken.net/console 创建完在 API Keys 页面能看到。文档在 https://taotoken.net/doc 。接入时你需要三件套配置项值说明Base URLhttps://taotoken.net/api所有请求的基础地址不带 UTMAPI Key控制台生成的sk-...放在Authorization: Bearer头里Model ID按需选择比如对话模型、编码模型这里有个关键点TaoToken 的鉴权用的是Authorization: Bearer key而 nginx 的 basic auth 用的也是Authorization: Basic base64。两者都占Authorization头所以如果你在 nginx 层做 basic auth同时后端又要用 Bearer 调 TaoToken就要注意别把请求头覆盖掉。常见做法是nginx 只对「进入你网关的入口」做 basic auth业务请求转发时把 basic auth 的Authorization换成 Bearer或者干脆让 basic auth 只保护静态资源/管理页API 走独立 location 不做 basic auth。这个取舍后面在配置里会体现。如果你用的是 Claude Code 这类工具接入时通常需要设置ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN或对应变量Base URL 填https://taotoken.net/apiKey 填控制台生成的。Coding Plan 相关入口在 https://taotoken.net/coding-plan 。这些工具如果跑在浏览器环境或跨域调用就会撞上本文的预检问题所以 nginx 骨架是通用的。2.3 确认 traefik 与 nginx 的职责边界在 k8s 里traefik 作为 ingress controller 负责把外部流量路由到 Service。我们的方案是traefik 只做路由不做 basic authbasic auth 和 CORS 预检处理全部下沉到 nginx。所以你要先把原来挂在 traefik 上的 basic auth middleware 摘掉改由 nginx 承担。这一步不做预检还是会被 traefik 拦。确认一下你的 nginx 会以 Deployment Service 形式部署在同一个 namespace示例用kube-appstraefik 的 IngressRoute 或 Ingress 指向这个 nginx Service 即可。后端业务 Service 的地址形如monitoring-system-service.kube-apps:8080按你实际情况替换。3. 可复制的 nginx traefik 配置骨架这一节是核心直接给可复制的片段。分三块nginx 的 ConfigMap含 nginx.conf 和 ngauth、nginx 的 Deployment/Service、traefik 指向 nginx 的配置。3.1 nginx ConfigMap预检放行 basic auth先看 nginx.conf 的关键部分。核心是在location /里判断$request_method OPTIONS是预检就直接返回 200 并带上 CORS 头不走 basic auth其他方法才走auth_basic。apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf namespace: kube-apps data: nginx.conf: | user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { default_type application/octet-stream; log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for; access_log /var/log/nginx/access.log main; sendfile on; keepalive_timeout 65; upstream monitors { server monitoring-system-service.kube-apps:8080; } server { listen 80; location / { if ($request_method OPTIONS) { add_header Access-Control-Allow-Origin $http_origin always; add_header Access-Control-Allow-Methods GET, POST, OPTIONS always; add_header Access-Control-Allow-Headers Authorization, Content-Type always; add_header Access-Control-Allow-Credentials true always; add_header Content-Length 0; add_header Content-Type text/plain; return 200; } auth_basic closed site; auth_basic_user_file /etc/nginx/ngauth; add_header Access-Control-Allow-Origin $http_origin always; add_header Access-Control-Allow-Credentials true always; proxy_pass http://monitors; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } } ngauth: | username:$apr1$xxxxxxxx$yyyyyyyyyyyyyyyyyyyy几个要点必须说清楚。第一Access-Control-Allow-Origin不要写死null或*当Allow-Credentials为true时*是无效的浏览器会拒绝。用$http_origin回显请求来源或者写死你的具体域名。第二Access-Control-Allow-Headers必须包含Authorization否则带 basic auth 的正式请求预检过不了。第三always参数保证即使返回非 2xx 也带上 CORS 头方便排查。第四ngauth里的内容替换成你 2.1 步生成的真实内容。注意if在 nginx 里属于 rewrite 模块放在 location 里做方法判断是常见用法但不要在里面写复杂逻辑。这里只做 OPTIONS 短路返回是安全的。3.2 nginx 的 Deployment 与 ServiceapiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx namespace: kube-apps spec: type: NodePort selector: app: nginx ports: - name: http port: 80 targetPort: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: kube-apps labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 volumeMounts: - name: config-volume mountPath: /etc/nginx/nginx.conf subPath: nginx.conf - name: config-volume mountPath: /etc/nginx/ngauth subPath: ngauth volumes: - name: config-volume configMap: name: nginx-conf items: - key: nginx.conf path: nginx.conf - key: ngauth path: ngauth这里用subPath把 ConfigMap 的两个 key 分别挂成文件比挂整个目录更干净。镜像建议用nginx:1.25这类较新版本老版本1.12也能跑但没必要。auth_basic_user_file指向/etc/nginx/ngauth和挂载路径对应。3.3 traefik 指向 nginxtraefik 侧只需要把原来指向业务 Service 的路由改成指向 nginx Service并且移除 basic auth middleware。以 IngressRoute 为例apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: app-route namespace: kube-apps spec: entryPoints: - web routes: - match: Host(app.example.com) kind: Rule services: - name: nginx port: 80如果你用的是标准 Ingress把 backend service 改成nginx:80即可。关键是这个路由上不要再挂basicAuthmiddleware。basic auth 已经在 nginx 里做了。3.4 本地 docker 先验证再上 k8s上 k8s 前强烈建议本地用 docker 跑一遍省得反复改 ConfigMapdocker run --name nginx-test \ -v /home/user/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \ -v /home/user/nginx/ngauth:/etc/nginx/ngauth:ro \ -p 8080:80 -d nginx:1.25把 nginx.conf 和 ngauth 放在/home/user/nginx/下访问http://localhost:8080看是否弹 basic auth 框再用 curl 测 OPTIONS 是否返回 200。本地通了再kubectl create -f configMap.yaml和kubectl create -f nginx.yaml。4. 验证请求curl 预检与浏览器实测配置写完不算完得验证。分两步curl 模拟预检浏览器实测正式请求。4.1 curl 测 OPTIONS 预检预检请求不带认证应该直接返回 200 并带 CORS 头curl -i -X OPTIONS http://app.example.com/api/data \ -H Origin: https://frontend.example.com \ -H Access-Control-Request-Method: GET \ -H Access-Control-Request-Headers: Authorization期望看到HTTP/1.1 200 OK Access-Control-Allow-Origin: https://frontend.example.com Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: Authorization, Content-Type Access-Control-Allow-Credentials: true如果这里返回 401说明 OPTIONS 还是被 basic auth 拦了回去检查if ($request_method OPTIONS)是否在auth_basic之前生效以及 traefik 层是否还挂着 basic auth middleware。4.2 curl 测带认证的正式请求正式请求要带 basic auth同时带 Origincurl -i http://app.example.com/api/data \ -H Origin: https://frontend.example.com \ -u username:password期望返回业务数据且响应头里有Access-Control-Allow-Origin和Access-Control-Allow-Credentials: true。如果返回 401检查ngauth文件内容是否正确、auth_basic_user_file路径是否对。4.3 浏览器实测打开你的前端页面在 DevTools 的 Network 面板看请求。预检请求OPTIONS应该是 200正式请求GET/POST带Authorization: Basic ...响应头 CORS 齐全。如果控制台还报 CORS 错误重点看响应头里Access-Control-Allow-Origin的值是不是和你页面的 Origin 完全一致协议、域名、端口都要对。4.4 AI 工具侧验证如果你的 AI 工具比如 Cline、Claude Code要通过这个网关调 TaoToken验证方式类似。以 curl 模拟工具请求curl -i https://app.example.com/v1/chat/completions \ -H Origin: https://your-tool.example.com \ -H Authorization: Bearer sk-你的TaoTokenKey \ -H Content-Type: application/json \ -d {model:你的ModelID,messages:[{role:user,content:hi}]}注意这里Authorization用的是 Bearer不是 Basic。如果你的 nginx 对 API 路径也做了 basic auth就会冲突。建议把 API 路径单独放一个 location不做 basic auth只做 CORS 和转发。模型对话入口在 https://taotoken.net/models 可以先用它验证 Key 是否可用再接入工具。5. 本篇常见报错排查配置过程中最容易撞的几个报错逐个对照。5.1 401 Unauthorized 出现在 OPTIONS 请求上这是最典型的。原因OPTIONS 请求被 basic auth 拦了。排查顺序先确认 traefik 路由上没挂 basic auth middleware再确认 nginx 里if ($request_method OPTIONS)块在auth_basic之前且return 200生效。可以用kubectl logs看 nginx access logOPTIONS 请求的 status 是不是 401。5.2local proxy failed或连接后端超时这个报错通常出现在 nginx 转发到后端 Service 时。检查upstream monitors里的地址monitoring-system-service.kube-apps:8080是否和实际 Service 名、namespace、端口一致。k8s 里跨 namespace 访问要带.namespace后缀。另外确认 nginx Pod 和后端 Service 在同一个集群网络内NetworkPolicy 没拦。5.3reading choices或响应体解析失败如果你在 AI 工具侧看到类似error reading choices的报错多半是网关返回的不是标准 JSON或者 CORS 头缺失导致浏览器拿不到响应体。先用 curl 直接打网关确认返回体是合法 JSON。如果 curl 正常但浏览器报错就是 CORS 头问题回去检查Access-Control-Allow-Origin是否回显了正确的 Origin。5.4 OAuth 或 Bearer 与 Basic 冲突当同一个请求既要 basic auth 又要 Bearer 时Authorization头只能有一个。表现是后端收到的是 Basic 而不是 Bearer或者反过来。解决办法把需要 Bearer 的 API 路径拆成独立 location不做 basic auth或者用 nginx 的proxy_set_header Authorization Bearer ...强制覆盖。但覆盖会丢掉 basic auth 信息所以更推荐路径拆分。5.5 预检通过但正式请求 CORS 失败预检 200 了正式请求却报 CORS。常见原因是正式请求的响应里没带Access-Control-Allow-Origin。检查add_header是否加在了正确的 location以及always参数是否带上。还有一种情况后端业务服务自己也加了 CORS 头和 nginx 的重复浏览器看到多个值会拒绝。用proxy_hide_header把后端的 CORS 头藏掉只保留 nginx 的。5.6 ConfigMap 更新后 nginx 没生效改了 ConfigMapnginx 不会自动 reload。执行kubectl rollout restart deployment/nginx -n kube-apps或者进 Pod 里nginx -s reload。注意subPath挂载的文件不会随 ConfigMap 更新自动同步重启 Pod 最稳。6. 把 AI 工具接入这套骨架的落地建议回到 AI 工具侧。这套 nginx traefik 骨架的价值在于它让「带 basic auth 的网关」和「跨域调用」能共存。你的 AI 工具无论是 Cline、Claude Code 还是自研前端只要走这个网关预检问题就解决了。接入时记住三件套Base URL 填https://taotoken.net/apiKey 用控制台生成的Model ID 按需选。如果工具支持自定义 Base URL直接填如果工具跑在浏览器里跨域确保它请求的域名走的是本文的 nginx 骨架。Coding Plan 适合长期编码和 Agent 场景入口 https://taotoken.net/coding-plan 。API Keys 管理在 https://taotoken.net/api-keys 接入文档在 https://taotoken.net/doc 。最后给个实操建议把 basic auth 只用在管理页或静态资源上API 路径单独拆 location 不做 basic auth用 Bearer 走 TaoToken 鉴权。这样既避免了Authorization头冲突也让 AI 工具接入更顺。配置改完记得kubectl rollout restart然后用第 4 节的 curl 命令逐条验证别跳过预检那一步。