在 WebFilter 类中抛出异常并在 ControllerAdvice 类中处理它

Mig*_*dez 3 java spring-webflux

我正在尝试实现一个WebFilter检查 JWT 的方法,如果检查失败或结果无效,则抛出异常。我有一个@ControllerAdvice处理这些异常的类。但这不起作用。

这是WebFilter班级:

@Component
public class OktaAccessTokenFilter implements WebFilter {

private JwtVerifier jwtVerifier;

   @Autowired
   public OktaAccessTokenFilter(JwtVerifier jwtVerifier) {
        this.jwtVerifier = jwtVerifier;
   }

   @Override
   public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return Optional.ofNullable(exchange.getRequest().getHeaders().get("Authorization"))
            .flatMap(list -> list.stream().findFirst())
            .filter(authHeader -> !authHeader.isEmpty() && authHeader.startsWith("Bearer "))
            .map(authHeader -> authHeader.replaceFirst("^Bearer", ""))
            .map(jwtString -> {
                try {
                    jwtVerifier.decodeAccessToken(jwtString);
                } catch (JoseException e) {
                    throw new DecodeAccessTokenException();
                }
                return chain.filter(exchange);
            }).orElseThrow(() -> new AuthorizationException());
      }
}
Run Code Online (Sandbox Code Playgroud)

以及异常处理程序:

@ControllerAdvice
public class SecurityExceptionHandler {

  @ExceptionHandler(AuthorizationException.class)
  public ResponseEntity authorizationExceptionHandler(AuthorizationException ex) {

    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();

  }

  @ExceptionHandler(DecodeAccessTokenException.class)
  public ResponseEntity decodeAccessTokenExceptionHandler(DecodeAccessTokenException ex) {

    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();

  }

}
Run Code Online (Sandbox Code Playgroud)

我认为,该类@ControllerAdvice无法处理WebFilter抛出的异常。因为,如果我将异常移至控制器,它就会起作用。

我已经为此更改了代码(目前):

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {

    Optional<String> authJwt = Optional.ofNullable(exchange.getRequest().getHeaders().get("Authorization"))
            .flatMap(list -> list.stream().findFirst())
            .filter(authHeader -> !authHeader.isEmpty() && authHeader.startsWith("Bearer "))
            .map(authHeader -> authHeader.replaceFirst("^Bearer", ""));

    if (authJwt.isPresent()) {
        String jwtString = authJwt.get();
        try {
            jwtVerifier.decodeAccessToken(jwtString);
        } catch (JoseException e) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().writeWith(Mono.empty());
        }
    } else {
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().writeWith(Mono.empty());
    }

    return chain.filter(exchange);
}
Run Code Online (Sandbox Code Playgroud)

您对这个问题有何看法?您知道另一种实现方法吗?

Mur*_*kan 5

您可以尝试@Order()为您的@ControllerAdvice@WebFilterbeans 定义 an ,并给予@ControllerAdvice更高的优先级。

但是,我不认为这是正确的方法,主要原因是@ControllerAdvice异常处理程序不返回反应类型。相反,我会定义一个 beanErrorWebExceptionHandler来实现。该处理程序由 spring-webflux 添加到反应流中,因此您无需担心优先级。有关详细信息,请参阅此答案