Handle Security exceptions in Spring Boot Resource Server

后端 未结 8 681
执念已碎
执念已碎 2021-01-31 05:36

How can I get my custom ResponseEntityExceptionHandler or OAuth2ExceptionRenderer to handle Exceptions raised by Spring security on a pure resource ser

8条回答
  •  花落未央
    2021-01-31 05:41

    As noted in previous comments the request is rejected by the security framework before it reaches the MVC layer so @ControllerAdvice is not an option here.

    There are 3 interfaces in the Spring Security framework that may be of interest here:

    • org.springframework.security.web.authentication.AuthenticationSuccessHandler
    • org.springframework.security.web.authentication.AuthenticationFailureHandler
    • org.springframework.security.web.access.AccessDeniedHandler

    You can create implementations of each of these Interfaces in order to customize the response sent for various events: successful login, failed login, attempt to access protected resource with insufficient permissions.

    The following would return a JSON response on unsuccessful login attempt:

    @Component
    public class RestAuthenticationFailureHandler implements AuthenticationFailureHandler
    {
      @Override
      public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
          AuthenticationException ex) throws IOException, ServletException
      {
        response.setStatus(HttpStatus.FORBIDDEN.value());
        
        Map data = new HashMap<>();
        data.put("timestamp", new Date());
        data.put("status",HttpStatus.FORBIDDEN.value());
        data.put("message", "Access Denied");
        data.put("path", request.getRequestURL().toString());
        
        OutputStream out = response.getOutputStream();
        com.fasterxml.jackson.databind.ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(out, data);
        out.flush();
      }
    }
    

    You also need to register your implementation(s) with the Security framework. In Java config this looks like the below:

    @Configuration
    @EnableWebSecurity
    @ComponentScan("...")
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter
    {
      @Override
      public void configure(HttpSecurity http) throws Exception
      {
        http
           .addFilterBefore(corsFilter(), ChannelProcessingFilter.class)
           .logout()
           .deleteCookies("JESSIONID")
           .logoutUrl("/api/logout")
           .logoutSuccessHandler(logoutSuccessHandler())
           .and()
           .formLogin()
           .loginPage("/login")
           .loginProcessingUrl("/api/login")
           .failureHandler(authenticationFailureHandler())
           .successHandler(authenticationSuccessHandler())
           .and()
           .csrf()
           .disable()
           .exceptionHandling()
           .authenticationEntryPoint(authenticationEntryPoint())
           .accessDeniedHandler(accessDeniedHandler());
      }
    
      /**
       * @return Custom {@link AuthenticationFailureHandler} to send suitable response to REST clients in the event of a
       *         failed authentication attempt.
       */
      @Bean
      public AuthenticationFailureHandler authenticationFailureHandler()
      {
        return new RestAuthenticationFailureHandler();
      }
    
      /**
       * @return Custom {@link AuthenticationSuccessHandler} to send suitable response to REST clients in the event of a
       *         successful authentication attempt.
       */
      @Bean
      public AuthenticationSuccessHandler authenticationSuccessHandler()
      {
        return new RestAuthenticationSuccessHandler();
      }
    
      /**
       * @return Custom {@link AccessDeniedHandler} to send suitable response to REST clients in the event of an attempt to
       *         access resources to which the user has insufficient privileges.
       */
      @Bean
      public AccessDeniedHandler accessDeniedHandler()
      {
        return new RestAccessDeniedHandler();
      }
    }
    

提交回复
热议问题