Spring ControllerAdvice和身份验证/授权异常处理



在我的Spring Boot应用程序中,我有以下web安全配置:

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off   
        http
            .headers().frameOptions().disable()
            .and()
                .antMatcher("/**").authorizeRequests()
                .antMatchers("/actuator/health").permitAll()
                .antMatchers("/actuator/**").hasAuthority(Authority.Type.ROLE_ADMIN.getName())
                .antMatchers("/login/**").permitAll()
                .anyRequest().authenticated()
            .and()
                .formLogin()
                    .loginPage("/login")
                    .loginProcessingUrl("/login")
                    .failureUrl("/login?error").permitAll()
            .and()
                .logout()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                    .logoutSuccessUrl("/login?logout")
            .and()
                .csrf().csrfTokenRepository(csrfTokenRepository()).ignoringAntMatchers("/login/**")
            .and()
                .addFilterBefore(corsFilter, ChannelProcessingFilter.class)
                .addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class)
                .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class)
                .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
        // @formatter:on
    }
....
}

ControllerAdvice:

@ControllerAdvice
public class GlobalControllerExceptionHandler  {
    private static final String ERROR = "error";
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Map<String, ErrorResponse> handleException(Exception exception) {
        return createResponseError(exception);
    }
    private Map<String, ErrorResponse> createResponseError(Exception exception) {
        final Map<String, ErrorResponse> responseError = new HashMap<String, ErrorResponse>();
        responseError.put(ERROR, new ErrorResponse(exception.getMessage()));
        return responseError;
    }
}

现在,当我试图通过匿名用户访问我的安全API URL时,我收到了以下错误:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri May 06 22:59:05 EEST 2016
There was an unexpected error (type=Forbidden, status=403).
Access Denied

我需要在ControllerAdvice中处理此类错误(以便返回JSON错误响应),而不是这个页面,它对所有其他异常都很好,但只对经过身份验证的用户有效。

如何通过我的GlobalControllerExceptionHandler处理此身份验证/授权错误?

ControllerAdvice s用于辅助Controller类,ExceptionHandler s用于处理Controller s抛出的异常。AuthenticationExceptionAccessDeniedException s通常由Spring Security的AbstractSecurityInterceptor抛出。因此,我猜您将无法使用ControllerAdvices捕获这些AuthenticationExceptions,因为ExceptionTranslationFilter已经捕获了它们并将它们转换为适当的HTTP响应。

更好的方法是在WebSecurityConfigurerAdapter中使用exceptionHandling。使用它,您可以配置AuthenticationEntryPointAccessDeniedHandler。在这里,对于拒绝访问的情况,我返回403 Forbidden,对于丢失身份验证令牌的情况,返回401 Unauthorized

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception { 
        http.exceptionHandling()
            .accessDeniedHandler((request, response, accessDeniedException) -> {
                response.sendError(HttpServletResponse.SC_FORBIDDEN);
            })
            .authenticationEntryPoint((request, response, authException) -> {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            });
    }
}

使用exceptionHandling,您可以将ExceptionTranslationFilter配置为使用accessDeniedHandler处理AccessDeniedException s,将authenticationEntryPoint配置为AuthenticationException s。查看ExceptionTranslationFilter以了解有关该过程的更多信息。

如果你不喜欢:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri May 06 22:59:05 EEST 2016
There was an unexpected error (type=Forbidden, status=403).
Access Denied

如果要自定义它,您应该提供ErrorController的实现,并为错误返回Map<String, ErrorResponse>

最新更新