首页 > 解决方案 > 无法为 JWT CustomClaimVerifier 抛出自定义异常消息

问题描述

我正在尝试使用JwtClaimsSetVerifierSpring Boot 2.1 给出的 JWT 令牌中的声明进行验证。问题是 Spring 总是抛出一个带有默认异常消息的异常:

{
    "error": "invalid_token",
    "error_description": "Cannot convert access token to JSON"
}

即使我创建了一个扩展的自定义异常ClientAuthenticationException,我也会收到相同的异常消息。

当 JWT 声明验证失败时,我想修改异常消息。这是我的配置类:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceserverConfig extends ResourceServerConfigurerAdapter{

    @Autowired
    private DataSource dataSource;

     @Override
       public void configure(HttpSecurity http) throws Exception {
          http.authorizeRequests().anyRequest().permitAll().and()
          .exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler());

       }


     @Bean
     public DataSource getDataSource() {

            return dataSource;
        }

     @Bean
     public JwtAccessTokenConverter accessTokenConverter() {
          JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
          converter.setSigningKey("qwerty123");
          converter.setJwtClaimsSetVerifier(jwtClaimsSetVerifier());
          return converter;
     }

     @Bean
      public AuthenticationFailureHandler authenticationFailureHandler()
      {
        return new RestAuthenticationFailureHandler();
      }

     @Bean
       public JwtClaimsSetVerifier jwtClaimsSetVerifier() {
          return new DelegatingJwtClaimsSetVerifier(Arrays.asList(customJwtClaimVerifier()));
       }

     @Bean
       public JwtClaimsSetVerifier customJwtClaimVerifier() {
          return new CustomClaimVerifier();
       }

     @Override
       public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
          TokenStore tokenStoreRes = new JdbcTokenStore(dataSource);
          resources.resourceId("RESOURCE").tokenStore(tokenStoreRes);
       }

       @Bean
       @Primary
       public DefaultTokenServices tokenJWTServices() {
          DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
          TokenStore tokenStoreRes = new JwtTokenStore(accessTokenConverter());
          defaultTokenServices.setTokenStore(tokenStoreRes);
          defaultTokenServices.setSupportRefreshToken(true);
          return defaultTokenServices;
       }


}

这是我的JWTClaimVerifier课:

public class CustomClaimVerifier implements JwtClaimsSetVerifier{

    @Autowired
    HttpServletRequest request;

    @Override
    public void verify(Map<String, Object> claims) throws InvalidTokenException {
        try {
            JsonParser parser = new JsonParser();
            String json = new Gson().toJson(claims.get("userdetails"));
            JsonElement menu = parser.parse(json);
            String menuList = menu.getAsJsonObject().get("menu").getAsString();
            boolean isMenuAccessible = validateAccessForMenu(request.getHeader("menuClicked"), menuList);
            if(!isMenuAccessible) {
                throw new InvalidTokenException("Invalid Permissions");
            }
        } catch (Exception e) {
            throw new InvalidTokenException(e.getMessage());
        }
    }
}

当 JWT 声明验证失败时,我想要一个带有自定义异常消息的异常,但我得到的只是 Spring Security 抛出的标准异常消息。

标签: springspring-bootspring-securityjwtspring-security-oauth2

解决方案


当 JWT 声明验证失败时,我想修改异常消息。

但是您确实收到了自定义异常消息。

您看到的消息是因为其他事情,在声明可以验证之前的事情,失败了。

如果您查看 中的decode(String)方法JwtAccessTokenConverter,您将看到在令牌字符串被解码为 Jwt 并且声明已被解析之后JwtClaimsSetVerifier调用了您的实现。如果在解码令牌时抛出异常,您将没有机会覆盖该异常。CustomClaimVerifier

是否要覆盖解码失败时抛出的默认异常消息?

不幸的是,似乎没有一种直接的方式来提供您自己的信息。也许你可以继承并用你自己的JwtAccessTokenConverter替换every :InvalidTokenException

public class CustomJwtAccessTokenConverter extends JwtAccessTokenConverter {

    @Override
    protected Map<String, Object> decode(String token) {
        Map<String, Object> pieces = null;

        try {
            pieces = super.decode(token);
        } catch(InvalidTokenException ex) {
            throw new InvalidTokenException("MY CUSTOM MESSAGE");
        }

        return pieces;
    }
}

推荐阅读