简体   繁体   English

Spring Security:安全性过滤器中引发的异常映射

[英]Spring Security: mapping of exceptions thrown inside security filter

I have custom security filter which serves as additional authorization step. 我有自定义的安全筛选器,可以用作其他授权步骤。

The filter checks if a user can be authorized and throws an exception if the user is not supposed to access the resource. 筛选器检查是否可以授权用户,如果不应该访问该用户,则引发异常。

The problem is that if I throw an exception from the filter - it doesn't get mapped to correct status code (in my case I need HTTP 403). 问题是, 如果我从过滤器中抛出异常则该异常不会被映射到正确的状态代码 (在我的情况下,我需要HTTP 403)。

I can't use @ControllerAdvice and @ExceptionHandler because security filters work before controller handling . 我不能使用@ControllerAdvice@ExceptionHandler因为安全过滤器在处理控制器之前起作用

I thought may be I'm doing it wrong and I shouldn't throw an exception, or I should throw a very specific one. 我以为是我做错了,我不应该抛出异常,或者我应该抛出一个非常具体的异常。

Q: Is there any way to automatically map exceptions from filters to proper status codes? 问:有什么方法可以自动将异常从过滤器映射到正确的状态代码? Or is there a way to implement the filter without exceptions? 还是有没有办法实现过滤器而没有例外?

Note: I also read this post , but from debug I see that my filter chain doesn't contain ExceptionTranslationFilter . 注意:我也阅读了这篇文章 ,但是从调试中我看到我的过滤器链不包含ExceptionTranslationFilter

Or is there a way to implement the filter without exceptions? 还是有没有办法实现过滤器而没有例外?

Obviously, you can directly write to response and return from the very point you catch an authentication or authorization failure. 显然,您可以直接写入响应并从遇到身份验证或授权失败的那一刻起返回。 Throwing exceptions then globally handling it seemed too much unnecessary overwork for me since I had only one JWT authentication filter implementing - AbstractAuthenticationProcessingFilter 抛出异常然后进行全局处理对我来说似乎是不必要的过度工作,因为我只有一个JWT身份验证过滤器实现-AbstractAuthenticationProcessingFilter

Whenever an authentication condition is not met , like JWT token parsing issue, missing token , malformed token etc , I simply log error , set HttpStatus and return null from attemptAuthentication method. 每当认证条件不能满足,像JWT令牌解析问题,缺少令牌,令牌畸形等,我只需登录错误,设定HttpStatus并返回nullattemptAuthentication方法。

This way my whole logic is encapsulated in single class. 这样,我的整个逻辑就封装在单个类中。 I also had to send 401 for all cases but error messages were different and that was handled by a simple utility method. 我还必须在所有情况下都发送401 ,但错误消息有所不同,这是通过简单的实用程序方法处理的。

I don't find any fault in throwing and then handling exceptions if you have to do that from many places in your application and in that case handler could be specified as in Nicholas Smith's answer. 如果您必须从应用程序的许多地方进行异常处理,那么在抛出异常然后处理异常方面我没有发现任何错误,在这种情况下,可以像Nicholas Smith的答案中那样指定处理程序。

The Spring recommended way is to have a @Component that implements AccessDeniedHandler and then in your class that extends WebSecurityConfigurerAdapter register it to the .accessDeniedHandler() in the configure(HttpSecurity ...) method. Spring推荐的方法是拥有一个实现AccessDeniedHandler@Component ,然后在扩展WebSecurityConfigurerAdapter的类WebSecurityConfigurerAdapter注册到configure(HttpSecurity ...)方法中的.accessDeniedHandler()中。 That's for 403 , if you want 401 errors to be wrapped as well then you need to extend Http401AuthenticationEntryPoint . 那是针对403 ,如果您还希望包装401错误,则需要扩展Http401AuthenticationEntryPoint I'll focus on 403 cases below. 我将在下面重点讨论403案例。

Your WebSecurityConfigurerAdapter 您的WebSecurityConfigurerAdapter

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

Your AccessDeniedHandler 您的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);
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM