答案是系统时间偏差超5分钟导致jwt签名验证失败;composer依赖packagist签发的jwt中exp/iat字段与本地时间比对,偏差超容忍窗口即拒收,清缓存、换镜像均无效,须用timedatectl校准并启用systemd-timesyncd等持久同步机制。

Composer报“Signature verification failed”是时钟偏移,不是缓存问题
系统时间偏差超过5分钟(快或慢)会直接导致JWT签名验证失败,现象是Signature verification failed、Token has expired或Token not active yet。这不是缓存损坏,清缓存、换镜像、重装Composer全无效——因为Packagist签发的JWT里exp和iat字段与本地时间比对,偏差超窗口即拒收。
验证方式:date对比curl -s https://worldtimeapi.org/api/ip | grep utc_datetime,偏差≥60秒就必须校准。临时ntpdate只能缓解,不持久。
- Linux:启用
systemd-timesyncd并确认服务运行中(sudo systemctl enable --now systemd-timesyncd) - macOS:打开“系统设置→日期与时间→自动设定日期与时间”
- WSL2:执行
sudo hwclock --hctosys临时同步;永久解法是在/etc/wsl.conf加[boot] systemd=true并重启 - Docker容器:修复宿主机时间,容器共享宿主机clock,容器内
date -s无效且破坏自动校准
CI/CD里偶发失败?不是缓存没清,是启动时钟未同步
GitHub Actions、GitLab CI等云环境虚拟机启动极快,NTP同步可能尚未完成就执行composer install,导致首次运行JWT验证失败,重试后通过——本质是初始系统时间不准,不是网络抖动或镜像延迟。
解决思路不是加--no-cache或删缓存,而是让作业等待时钟稳定:
- GitHub Actions:在
steps开头加run: sudo timedatectl set-ntp true && sleep 5 - GitLab CI:用
before_script执行timedatectl status | grep "System clock synchronized"轮询直到返回yes - 避免在CI脚本里写
date -s——它不持久,且可能被后续systemd-timesyncd覆盖
为什么composer clear-cache对时钟问题完全没用?
composer clear-cache只删~/.composer/cache/下的ZIP包和元数据文件,但JWT验证发生在HTTP响应解析阶段,靠的是PHP读取系统时间戳去比对JWT载荷,跟缓存目录内容无关。即使你删光整个缓存,只要date输出错误,下一次请求照样失败。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
常见误操作:
- 看到
Signature verification failed立刻跑composer clear-cache→ 白忙活 - 改了镜像源以为能绕过验证 → Packagist所有官方源(含镜像)都用同一套JWT签发机制
- 怀疑CA证书过期 → 这是另一类错误(
Invalid signature),和时钟偏移无关
时钟修复后,还要注意镜像元数据缓存的“假同步”
系统时间校准后,JWT验证通过,但你仍可能遇到“明明镜像已更新,composer update却装不到新版”的现象——这是Composer默认复用15分钟内不过期的packages.json缓存,不是时钟问题,而是元数据缓存策略。
此时该用composer update --refresh(仅Composer ≥ 2.5支持),它只丢弃packages.json和provider-*.json,不删ZIP包,快且精准。执行前确认两件事:
-
composer config -g repos.packagist.url输出是你配的镜像地址(注意是repos复数,不是repo) - 项目根目录
composer.json里没有"repositories"字段,否则会劫持全局配置,--refresh也拉错源
老版本(≤2.4)不支持--refresh,只能手动删对应缓存子目录:rm -rf $(composer config --global cache-dir)/repo/https---mirrors-aliyun-com-composer。










