Spring Boot REST API/Spring Security:在身份验证失败时返回自定义消息

clo*_*ker 2 rest spring jersey spring-security spring-boot

我有一个使用Jersey作为JAX-RS实现的Spring Boot应用程序.这是我的安全配置:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired TokenAuthenticationProvider tokenAuthenticationProvider;

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(tokenAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(new AuthenticationTokenFilter(), BasicAuthenticationFilter.class)
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/dataHub/**")
                .authenticated();
    }
}
Run Code Online (Sandbox Code Playgroud)

我想要做的是有一种方法来捕获我的TokenAuthenticationProvider抛出的异常,并将它们转换为我们已经同意的标准化JSON格式.有没有办法做到这一点?我试着添加一个自定义的AuthenticationFailureHandler,但是无法让它工作.

Dan*_*ski 13

WebSecurityConfigurerAdapter appraoch

HttpSecurity类有一个叫做方法exceptionHandling可用于覆盖默认行为.以下示例介绍了如何自定义响应消息.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        // your custom configuration goes here
        .exceptionHandling()
        .authenticationEntryPoint((request, response, e) -> {
            String json = String.format("{\"message\": \"%s\"}", e.getMessage());
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write(json);                
        });
}
Run Code Online (Sandbox Code Playgroud)

@ControllerAdvice appraoch - 为什么它在这种情况下不起作用

起初我考虑过@ControllerAdvice捕获整个应用程序的身份验证异常.

import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;

@ControllerAdvice
public class AuthExceptionHandler {

    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(AuthenticationException.class)
    @ResponseBody
    public String handleAuthenticationException(AuthenticationException e) {
        return String.format("{\"message\": \"%s\"}", e.getMessage());
    }

}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,JSON是手动构建的,但您可以简单地返回一个POJO,它将映射到JSON,就像从常规REST控制器一样.既然Spring 4.3,你也可以使用@RestControllerAdvice,这是一个组合@ControllerAdvice@ResponseBody.

但是,此方法不起作用,因为异常是AbstractSecurityInterceptorExceptionTranslationFilter抛出并在到达任何控制器之前处理的.