【问题标题】:Throw an exception in a WebFilter class and handle it in a ControllerAdvice class在 WebFilter 类中抛出异常并在 ControllerAdvice 类中处理它
【发布时间】:2018-11-05 15:02:18
【问题描述】:

我正在尝试实现一个 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());
      }
}

以及异常处理程序:

@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();

  }

}

我认为,@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);
}

你怎么看这个问题?你知道另一种实现方式吗?

【问题讨论】:

    标签: java spring-webflux


    【解决方案1】:

    我已经尝试过了,但我遇到了 CORS 错误 这是错误:

    从源“http://localhost:4200”访问“http://localhost:8084/users/files”处的 XMLHttpRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。

    【讨论】:

    • 在哪里可以解决您的 cors 问题?我正在尝试同样的问题。谢谢
    【解决方案2】:

    我在 webflux 中遇到了同样的问题,你不想在 webfilter 中抛出直接异常或返回单声道错误),但是你想将响应设置为包含异常的单声道错误(接近你的完成了)。这将允许在请求工作流的正确部分引发异常,因此它将冒泡到您的其余控制器建议

    public class YourFilter implements WebFilter{
    
        @Override
        public Mono<Void> filter(final ServerWebExchange exchange, final WebFilterChain chain){
            exchange.getResponse().writeWith(Mono.error(new YouException()));
    
            return chain.filter(exchange);
        }
    }
    

    【讨论】:

      【解决方案3】:

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

      但是,我不认为这是要走的路,主要原因是@ControllerAdvice 异常处理程序不返回反应类型。相反,我会定义一个实现ErrorWebExceptionHandler 的bean。这个处理程序是由 spring-webflux 添加到响应流中的,所以你不需要担心优先级。详情请见this answer

      【讨论】:

      • 谢谢!我实施了第二种方法,效果很好。
      猜你喜欢
      • 1970-01-01
      • 2022-10-14
      • 2019-07-06
      • 1970-01-01
      • 2018-12-22
      • 2018-07-13
      • 1970-01-01
      • 2011-12-12
      相关资源
      最近更新 更多