Composer 不支持原生 JWT 鉴权,必须由反向代理(如 Nginx)校验 JWT 后转换为 Basic Auth 头转发;auth.json 中需用 http-basic 字段填 JWT 作 username、password 留空,域名须与仓库 URL 完全一致。

企业级 Composer 私有镜像(如 Satis 或 Private Packagist)本身不提供 JWT 鉴权能力——它只支持 HTTP Basic、OAuth Token 或 IP 白名单等传统方式。JWT 必须由你前置的反向代理(如 Nginx、Traefik)或 API 网关统一处理,Composer 客户端完全感知不到 JWT,它只认 http-basic 或 github-oauth 这类原生认证机制。
为什么不能在 Composer 里直接用 JWT?
Composer 的 auth 流程是静态、无状态、无中间件的:它读 auth.json → 拼出 Authorization: Basic ... 或 Authorization: Bearer ... → 直接发请求。它不执行 JS、不调用 SDK、不解析 JWT payload,也不支持自定义鉴权逻辑。所谓“JWT 鉴权”,实际是让反向代理校验 JWT 后,透传或转换为 Composer 能理解的凭据(如 Basic Auth 头),再转发给后端仓库服务。
- Composer 2.9.6 及所有已知版本,
auth.json中没有jwt-token字段,填了也静默忽略 -
composer config http-basic.repo.example.com token ""是唯一被识别的 JWT 兼容写法——前提是你的反向代理把Bearer xxx解析后,重写为Authorization: Basic base64(token:) - 直接往
repositories里写"options": {"auth": {"bearer": "xxx"}}无效,Composer 不解析该字段
Nginx 反向代理如何透传并转换 JWT?
核心思路:Nginx 收到带 Authorization: Bearer <jwt> 的请求 → 用 auth_request 或 Lua 模块校验 JWT → 成功后注入 Authorization: Basic ... 头,再 proxy_pass 到 Satis 静态目录或 Private Packagist 实例。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 必须启用
ngx_http_auth_request_module或 OpenResty +resty-jwt,原生 Nginx 不支持 JWT 解析 - 校验失败时返回
401 Unauthorized,Composer 会提示Authentication required,行为一致 - 关键配置片段(Nginx):
location / { auth_request /auth; auth_request_set $auth_status $upstream_status; proxy_set_header Authorization "Basic $encoded_credential"; proxy_pass https://satis-backend/; } location = /auth { internal; proxy_pass https://jwt-validator/; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Sent-From $host; } -
$encoded_credential需通过 map 或 Lua 从 JWT payload 提取 user/token,base64 编码后拼成user:token
auth.json 怎么配才能对接 JWT 网关?
你依然得用 http-basic 字段,但 username 填 JWT 字符串,password 留空——这是绕过 Composer 校验、触发网关 JWT 解析的“事实标准”。
- 正确写法:
{ "http-basic": { "packages.internal": { "username": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "password": "" } } } - 域名 key 必须和仓库 URL 主机名完全一致:
"packages.internal"对应https://packages.internal/packages.json,多一个www.或端口都不行 - 权限必须是
600:chmod 600 ~/.composer/auth.json,否则 Composer 直接跳过 - CI 环境别硬编码 JWT,应从 Vault 或 K8s Secret 注入
COMPOSER_AUTH环境变量,内容为 JSON 字符串
Satis 静态仓库怎么配合 JWT 网关?
Satis 本身无鉴权,所有安全责任落在网关层。但你必须确保生成的静态文件可被网关无差别托管,且元数据结构不破坏 JWT 验证链。
-
satis.json中"archive": {"prefix-url": "https://packages.internal/dist/"}的域名,必须和 JWT 网关监听域名一致,否则 ZIP 下载请求会绕过网关直连后端 - 禁用
"require-all": true,否则packages.json过大,网关 JWT 校验耗时增加,易超时 - Web 服务器(Nginx)必须设置
application/jsonMIME 类型,否则 Composer 读packages.json时解析失败,报Unable to load package list - ZIP 包路径(如
/dist/vendor-package-1.2.3.zip)也要经网关,不能裸露在公网——否则攻击者绕过 JWT 直接下载内部包
真正难的不是 JWT 本身,而是让网关、Satis、Composer 三端对“同一个 token”达成语义共识:网关认为合法,Satis 不拒绝路径,Composer 不因头格式崩溃。漏掉任意一环,就会出现 Could not find package 或 403 Forbidden 这种看似随机实则确定的故障。

















