如何在Quarkus中自定义JWT解析?处理sub非字符串类型问题
问题
使用SmallRye JWT作为Quarkus应用的授权工具,仅负责验证JWT令牌(不生成)。当前遇到的问题是:传入的令牌中sub声明为数值类型(如45),但SmallRye JWT解析器要求该声明必须是java.lang.String类型,导致验证失败。无法修改令牌生成方,需要在Quarkus应用端做适配。
报错信息
Caused by: org.jose4j.jwt.consumer.InvalidJwtException: JWT (claims->{"iss":"...","iat":...,"exp":...,"nbf":...,"jti":"...","sub":45,"prv":"...","pid": ...}) rejected due to invalid claims or other invalid content. Additional details: [[18] The value of the 'sub' claim is not the expected type (1517 - Cannot cast java.lang.Long to java.lang.String)]
当前配置(application.properties)
smallrye.jwt.verify.key-format=JWK smallrye.jwt.verify.key.location=JWTSecret.jwk smallrye.jwt.verify.algorithm=HS256
解决方案
方法1:自定义JWT Claim映射器
通过实现ClaimMapper接口,手动拦截并转换sub声明的类型:
- 创建自定义映射器类:
import io.smallrye.jwt.auth.principal.ClaimMapper; import io.smallrye.jwt.auth.principal.JWTCallerPrincipal; import io.smallrye.jwt.auth.principal.ParseException; import jakarta.enterprise.context.ApplicationScoped; import java.util.Map; @ApplicationScoped public class CustomSubClaimMapper implements ClaimMapper { @Override public void mapClaims(Map<String, Object> claims, JWTCallerPrincipal principal) throws ParseException { Object subValue = claims.get("sub"); // 若sub为非字符串类型,转换为字符串后存回 if (subValue != null && !(subValue instanceof String)) { claims.put("sub", String.valueOf(subValue)); } } }
- 在配置文件中指定使用该映射器:
smallrye.jwt.claim-mapper=com.yourpackage.CustomSubClaimMapper
方法2:调整JwtConsumer验证规则
通过扩展JwtConsumerBuilderCustomizer,修改JWT消费者的验证逻辑,允许sub为数值类型并完成转换:
- 创建自定义消费者配置类:
import io.smallrye.jwt.build.JwtConsumerBuilderCustomizer; import jakarta.enterprise.context.ApplicationScoped; import org.jose4j.jwt.consumer.JwtConsumerBuilder; import org.jose4j.jwt.consumer.JwtContext; @ApplicationScoped public class CustomJwtConsumerCustomizer implements JwtConsumerBuilderCustomizer { @Override public void customize(JwtConsumerBuilder builder) { builder.setCustomValidator(context -> { JwtContext jwtContext = (JwtContext) context; Object sub = jwtContext.getJwtClaims().getClaimValue("sub"); if (sub != null) { // 将数值类型的sub转为字符串并存回 jwtContext.getJwtClaims().setClaim("sub", String.valueOf(sub)); } return null; // 返回null表示验证通过 }); } }
验证
完成配置后重启Quarkus应用,测试传入带有数值类型sub的JWT令牌,此时解析器应能正常完成验证流程。
内容的提问来源于stack exchange,提问作者E. Dn
相关产品推荐
相关产品推荐

