【问题标题】:custom exception is not passing through Advice control in spring boot自定义异常未通过 Spring Boot 中的 Advice 控件
【发布时间】:2021-09-28 12:54:51
【问题描述】:

我正在尝试自定义抛出的异常,但它不在通知控件中。

TokenExpiredException 异常 应该在控制器通知中处理,但返回一个常见的、未处理的错误。

JWTValidarFilter:

public class JWTValidarFilter extends BasicAuthenticationFilter{

private static final String HEADER_ATRIBUTO = "Authorization";

private static final String ATRIBUTO_PREFIXO = "Bearer ";

public JWTValidarFilter(AuthenticationManager authenticationManager) {
    super(authenticationManager);
}

@Override
protected void doFilterInternal(HttpServletRequest request, 
        HttpServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    
    String atributo = request.getHeader(HEADER_ATRIBUTO);
            
    if(atributo == null) {
        chain.doFilter(request, response);
        return;
    }
    
    if(!atributo.startsWith(ATRIBUTO_PREFIXO)) {
        chain.doFilter(request, response);
        return;
    }
    
    String token = atributo.replace(ATRIBUTO_PREFIXO, "");
    
    UsernamePasswordAuthenticationToken authenticationToken = getAuthenticationToken(token);
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    chain.doFilter(request, response);
    
    
}

private UsernamePasswordAuthenticationToken getAuthenticationToken(String token) {
    
    
    try {
        String usuario = JWT.require(Algorithm.HMAC512(JWTAutenticarFilter.TOKEN_SENHA))
                .build()
                .verify(token)
                .getSubject();
        if(usuario == null) {
            return null;
        }
        
        return new UsernamePasswordAuthenticationToken(usuario, null, new ArrayList<>());

    } catch (TokenExpiredException e) {
        throw new TokenExpiredException("Token expirado!");
    }
    
}

}

CustomizeResponseEntityExceptionHandler:

@ControllerAdvice
@RestController
public class CustomizeResponseEntityExceptionHandler extends ResponseEntityExceptionHandler{

    @ExceptionHandler(Exception.class)
    public final ResponseEntity<ExceptionResponse> handleAllExcepetions(Exception ex, WebRequest request){
        ExceptionResponse exceptionResponse = 
                new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
        
        return new ResponseEntity<>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(InvalidJwtAuthenticationException.class)
    public final ResponseEntity<ExceptionResponse> invalidJwtAuthenticationException(Exception ex, WebRequest request){
        ExceptionResponse exceptionResponse = 
                new ExceptionResponse(new Date(), 
                        ex.getMessage(), 
                        request.getDescription(false));
        
        return new ResponseEntity<>(exceptionResponse, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(TokenExpiredException.class)
    public final ResponseEntity<ExceptionResponse> TokenExpiredException(TokenExpiredException ex, WebRequest request){
        ExceptionResponse exceptionResponse = 
                new ExceptionResponse(new Date(), 
                        ex.getMessage(), 
                        request.getDescription(true));
        
        return new ResponseEntity<>(exceptionResponse, HttpStatus.UNAUTHORIZED);
    }

    
    @ExceptionHandler(HttpClientErrorException.class)
    public ResponseEntity<String> handleException(HttpClientErrorException ex) throws HttpClientErrorException {
        System.out.println("*******Exception Occured: *************" + ex);
        return ResponseEntity
                .status(HttpStatus.UNAUTHORIZED)
                .body(" -----DD------ Exception: " + ex.getLocalizedMessage());
    }
}

2021-09-28 10:13:38.729 错误 25385 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]:Servlet.service() 用于 servlet [dispatcherServlet]在路径 [] 的上下文中抛出异常 com.auth0.jwt.exceptions.TokenExpiredException:令牌过期!

【问题讨论】:

  • 您是否尝试过从CustomizeResponseEntityExceptionHandler 中删除@RestController。它不是必需的,可能会导致问题。
  • 是的,它没有改变任何东西......
  • 那么我的猜测是问题在于@ControllerAdvice 仅适用于@Controller 类,而@ExceptionHandler 仅处理控制器抛出的异常。您的异常是由自定义 BasicAuthenticationFilter 引发的。
  • 知道了,我该如何处理这个异常?
  • 请记住,这只是我的猜测。我会尝试另一种方法来做到这一点。

标签: java spring-boot exception


【解决方案1】:

尝试按如下方式构建自定义AuthenticationFailureHandler

public class CustomAuthenticationFailureHandler 
  implements AuthenticationFailureHandler {
 
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
       AuthenticationException exception) throws IOException, ServletException {

        Throwable cause = exception.getCause();
        ExceptionResponse exceptionResponse = null;

        if (cause instanceOf InvalidJwtAuthenticationException) {
          response.setStatus(HttpStatus.BAD_REQUEST.value());
          exceptionResponse = new ExceptionResponse(new Date(), 
                cause.getMessage(), 
                request.getDescription(false));
        } else if (cause instanceOf TokenExpiredException) {
          response.setStatus(HttpStatus.UNAUTHORIZED.value());
          exceptionResponse = new ExceptionResponse(new Date(), 
                ex.getMessage(), 
                request.getDescription(true));
        } else {
          // additional logic here
        }

        response.getOutputStream().println(objectMapper.writeValueAsString(exceptionResponse));
    }
}

那么你需要在@Configuration类中注册它:

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

【讨论】:

    【解决方案2】:

    您无法使用控制器建议来捕获身份验证异常(至少不那么简单:-)。身份验证异常发生在整个 Spring 异常处理程序初始化之前。以下是如何解决相关问题的类似讨论:

    Spring MVC (or Spring Boot). Custom JSON response for security related exceptions like 401 Unauthorized or 403 Forbidden)

    【讨论】:

      猜你喜欢
      • 2019-12-12
      • 2019-12-10
      • 2018-08-28
      • 2014-12-16
      • 2021-07-10
      • 2019-06-03
      • 1970-01-01
      • 1970-01-01
      • 2020-05-26
      相关资源
      最近更新 更多