错误信息
Wrong number of segments
也可能输出为
- UnexpectedValueException: Wrong number of segments
- Unexpected control character found
打印时会带上类名前缀:“UnexpectedValueException: Wrong number of segments”。带有 `Bearer` 前缀的情况则会产生“Unexpected control character found”(一个 `DomainException`)。
firebase/php-jwt (PHP) — UnexpectedValueException from JWT::decode
含义
`JWT::decode` 按点号拆分输入后,得到的不是恰好三个部分,因此输入不是紧凑格式的 JWS,其他内容都没有检查。在 PHP 应用中,最常见的来源是空字符串:Web 服务器没有把 `Authorization` 请求头传给 PHP,代码于是回退为 `''`。仍带有 `Bearer ` 前缀的令牌虽然有三段,但会在下一步失败,通常是 JSON 解码器报出“Unexpected control character found”。
原因
Authorization 请求头没有到达 PHP
常见搭配 PHP-FPM 或 CGI 的 Apache 会去掉 `Authorization`,除非配置为传递它,一些主机控制面板也会这样做。客户端发送了这个请求头,但 `$_SERVER['HTTP_AUTHORIZATION']` 并未设置。
该值不是 JWT
常见会话 ID、不透明的 OAuth 访问令牌、API 密钥,或者尚未拿到令牌的 JavaScript 客户端发送的 `"null"`。
字符串中残留了认证方案或引号
偶见传入整个请求头的值,或者带引号的 JSON 编码令牌,都会导致第一段解析失败。
修复方法
- 1.
稳妥地读取请求头并校验格式
在不同服务器配置存放该请求头的各个位置查找,只接受 `Bearer <three base64url segments>`,否则返回 401。
php function bearerToken(): ?string { $header = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] // Apache + mod_rewrite ?? (function_exists('apache_request_headers') ? (apache_request_headers()['Authorization'] ?? '') : ''); if (!preg_match('/^Bearer\s+([A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*)$/', $header, $m)) { return null; } return $m[1]; } - 2.
让 Apache 传递该请求头
`CGIPassAuth On`(Apache 2.4.13+)或一条重写规则可以把 `Authorization` 暴露给 PHP。
text # Apache with PHP-FPM / CGI: pass the Authorization header through CGIPassAuth On # or, with mod_rewrite: RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]