【问题标题】:Spring Security: mapping of exceptions thrown inside security filterSpring Security:安全过滤器内抛出的异常的映射
【发布时间】:2018-06-03 02:33:49
【问题描述】:

我有自定义安全过滤器,用作额外的授权步骤。

过滤器检查用户是否可以被授权,如果用户不应该访问资源,则抛出异常。

问题在于,如果我从过滤器中抛出异常 - 它不会映射到正确的状态代码(在我的情况下,我需要 HTTP 403)。

我不能使用@ControllerAdvice 和@ExceptionHandler,因为security filters work before controller handling。

我想可能是我做错了,我不应该抛出异常,或者我应该抛出一个非常具体的异常。

问:有没有办法自动将过滤器中的异常映射到正确的状态代码?或者有没有办法实现无例外的过滤器?

注意:我也读过this post,但从调试中我看到我的过滤器链不包含ExceptionTranslationFilter。

【问题讨论】:

  • 你抛出了什么异常?显示您的异常代码。

标签: java spring security spring-security http-status-codes


【解决方案1】:

或者有没有办法实现无异常的过滤器?

显然,您可以直接写入响应并从捕获身份验证或授权失败的那一刻返回。抛出异常然后全局处理它对我来说似乎太多不必要的过度工作,因为我只有一个 JWT 身份验证过滤器实现 - AbstractAuthenticationProcessingFilter

只要不满足身份验证条件,例如 JWT 令牌解析问题、丢失令牌、格式错误的令牌等,我只需记录错误,设置 HttpStatus 并从 attemptAuthentication 方法返回 null。

这样我的整个逻辑就被封装在一个类中。对于所有情况,我还必须发送401,但错误消息不同,并且由一个简单的实用程序方法处理。

如果您必须从应用程序中的许多地方执行此操作,我在抛出然后处理异常方面没有发现任何错误,在这种情况下,可以按照 Nicholas Smith 的回答指定处理程序。

【讨论】:

    【解决方案2】:

    推荐的Spring 方法是拥有一个实现AccessDeniedHandler 的@Component,然后在您的扩展WebSecurityConfigurerAdapter 的类中将其注册到configure(HttpSecurity ...) 方法中的.accessDeniedHandler()。这是针对403 的,如果您还想包装401 错误,那么您需要扩展Http401AuthenticationEntryPoint。我将重点关注下面的403 案例。

    您的 WebSecurityConfigurerAdapter

    @Override
      protected void configure(final HttpSecurity http) throws Exception {
        ...
        http
            .csrf().disable()
            .exceptionHandling().authenticationEntryPoint(<YOUR Http401AuthenticationEntryPoint>)
            .and()
            .exceptionHandling().accessDeniedHandler(<YOUR ACCESS DENIED HANDLER>);
        ...
      }
    

    您的 AccessDeniedHandler

    @Override
      public void handle(HttpServletRequest request,
                         HttpServletResponse response,
                         AccessDeniedException accessDeniedException) throws IOException, ServletException {
    
        response.setHeader("Content-Type", "application/hal+json;charset=UTF-8");
        response.getOutputStream()
            .print(objectMapper
                .writeValueAsString("Access Denied");
        response.setStatus(403);
      }
    

    【讨论】:

    • 是否需要满足一些额外的条件? AccessDeniedHandler 不会被调用。它被声明为@Component 并通过 DI 自动连接到我的配置中。我在过滤器中放入的AccessDeniedException 与handle() 中的相同。
    • 你是如何创建处理程序的?我们通过构造函数依赖注入来做到这一点。
    • 我也是通过构造函数注入来实现的。但我想这不是问题。可能是你有一些我没有的额外配置。
    • 可能,我记得设置起来有些棘手(即诅咒的一天)。我将尝试创建一个使其正常工作的最小示例。
    猜你喜欢
    • 2018-06-04
    • 1970-01-01
    • 2021-08-09
    • 2017-04-20
    • 2021-12-05
    • 2012-01-30
    • 1970-01-01
    • 2016-03-14
    • 2020-06-01
    相关资源
    最近更新 更多