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
}