在我的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网址时,我收到以下错误:

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用于协助Controller类,而ExceptionHandler用于处理Controller引发的异常。 AuthenticationExceptionAccessDeniedException通常由Spring Security的AbstractSecurityInterceptor抛出。因此,我猜测您将无法使用AuthenticationException捕获这些ControllerAdvice,因为ExceptionTranslationFilter已经捕获了它们并将其转换为适当的HTTP响应。

更好的方法是在exceptionHandling中使用WebSecurityConfigurerAdapter。使用它,您可以配置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,将authenticationEntryPoint用于AuthenticationException。窥视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>

08-28 14:25