错误信息
token is malformed: token contains an invalid number of segments
也可能输出为
- token is malformed: could not base64 decode header: illegal base64 data at input byte 6
- token contains an invalid number of segments
v5 会加上前缀“token is malformed: ”。v4 只打印内部文本,例如“token contains an invalid number of segments”。“illegal base64 data at input byte N”中的字节偏移量指向第一个非法字符。
golang-jwt/jwt (Go) — jwt.ErrTokenMalformed
含义
golang-jwt 连令牌的结构都读不出来。“invalid number of segments”表示字符串中不是恰好两个点;“could not base64 decode header”表示第一段不是 base64url——典型原因是还带着 `Bearer ` 前缀(偏移量为 6 的字节就是那个空格)。在 v5 中,这些错误被包装在 `jwt.ErrTokenMalformed` 中;此时还没有查找任何密钥。
原因
整个 Authorization 请求头都被拿去解析
常见`r.Header.Get("Authorization")` 返回的是 `Bearer eyJ…`。如果直接传给 `jwt.Parse`,其中的空格会让头部那一段变成无效的 base64。
该值不是 JWT
常见到达解析器的是不透明的 OAuth 访问令牌、会话 ID、API 密钥或空的请求头。只有由三段 base64url 组成的字符串才是 JWS 令牌。
有五段的加密令牌(JWE)
偶见一些身份提供商会对令牌加密。golang-jwt 只处理签名令牌;应先解密 JWE(例如使用 go-jose),再解析其中嵌套的 JWS。
令牌被截断了
偶见数据库列、Cookie 大小限制(4 KB)或日志行截断了令牌,丢掉了最后一段或最后一个点。
修复方法
- 1.
使用 request 提取器
`github.com/golang-jwt/jwt/v5/request` 会以不区分大小写的方式去掉 `Bearer` 方案前缀,并在根本没有令牌时返回 `request.ErrNoTokenInRequest`。
go import "github.com/golang-jwt/jwt/v5/request" token, err := request.ParseFromRequest(r, request.OAuth2Extractor, keyfunc, request.WithParser(jwt.NewParser(jwt.WithValidMethods([]string{"ES256"})))) if err != nil { http.Error(w, "unauthorized", http.StatusUnauthorized) return } - 2.
解析前先校验格式
数一数点的个数,就能区分 JWS(2 个)、JWE(4 个)和无效数据。只要不是你能处理的令牌,一律返回 401。
go raw := strings.TrimSpace(strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")) switch strings.Count(raw, ".") { case 2: // JWS: parse it case 4: // JWE: decrypt first (go-jose), golang-jwt does not handle encrypted tokens default: http.Error(w, "unauthorized", http.StatusUnauthorized) return }