func consumerVerify()

in plugins/wasm-go/extensions/jwt-auth/handler/verify.go [64:172]


func consumerVerify(consumer *cfg.Consumer, verifyTime time.Time, header HeaderProvider, log Logger) error {
	tokenStr := extractToken(*consumer.KeepToken, consumer, header, log)
	if tokenStr == "" {
		return &ErrDenied{
			msg:    fmt.Sprintf("jwt is missing, consumer: %s", consumer.Name),
			denied: deniedJWTMissing,
		}
	}

	// 当前版本的higress暂不支持jwe,此处用ParseSigned
	token, err := jwt.ParseSigned(tokenStr)
	if err != nil {
		return &ErrDenied{
			msg: fmt.Sprintf("jwt parse failed, consumer: %s, token: %s, reason: %s",
				consumer.Name,
				tokenStr,
				err.Error(),
			),
			denied: deniedJWTVerificationFails,
		}
	}

	// 此处可以直接使用 JSON 反序列 jwks
	jwks := jose.JSONWebKeySet{}
	err = json.Unmarshal([]byte(consumer.JWKs), &jwks)
	if err != nil {
		return &ErrDenied{
			msg: fmt.Sprintf("jwt parse failed, consumer: %s, token: %s, reason: %s",
				consumer.Name,
				tokenStr,
				err.Error(),
			),
			denied: deniedJWTVerificationFails,
		}
	}

	out := jwt.Claims{}
	rawClaims := map[string]any{}

	// 提前确认 kid 状态
	var kid string
	var key jose.JSONWebKey
	for _, header := range token.Headers {
		if header.KeyID != "" {
			kid = header.KeyID
			break
		}
	}
	// 没有 kid 时选择第一个 key
	if kid == "" {
		key = jwks.Keys[0]
	}

	keys := jwks.Key(kid)
	if len(keys) == 0 { // kid 不存在时选择第一个 key
		key = jwks.Keys[0]
	} else {
		key = keys[0]
	}

	// Claims 支持直接传入 jose 的 jwk
	// 无需额外调用verify,claims内部已进行验证
	err = token.Claims(key, &out)
	if err != nil {
		return &ErrDenied{
			msg: fmt.Sprintf("jwt verify failed, consumer: %s, token: %s, reason: %s",
				consumer.Name,
				tokenStr,
				err.Error(),
			),
			denied: deniedJWTVerificationFails,
		}
	}
	token.UnsafeClaimsWithoutVerification(&rawClaims)

	if out.Issuer != consumer.Issuer {
		return &ErrDenied{
			msg: fmt.Sprintf("jwt verify failed, consumer: %s, token: %s, reason: issuer does not equal",
				consumer.Name,
				tokenStr,
			),
			denied: deniedJWTVerificationFails,
		}
	}

	// 检查是否过期
	err = out.ValidateWithLeeway(
		jwt.Expected{
			Issuer: consumer.Issuer,
			Time:   verifyTime,
		},
		time.Duration(*consumer.ClockSkewSeconds)*time.Second,
	)
	if err != nil {
		return &ErrDenied{
			msg: fmt.Sprintf("jwt verify failed, consumer: %s, token: %s, reason: %s",
				consumer.Name,
				tokenStr,
				err.Error(),
			),
			denied: deniedJWTExpired,
		}
	}

	if consumer.ClaimsToHeaders != nil {
		claimsToHeader(rawClaims, *consumer.ClaimsToHeaders)
	}
	return nil
}