如何在纯资源服务器上获取自定义ResponseEntityExceptionHandler或OAuth2ExceptionRenderer处理Spring安全性引发的异常?
ResponseEntityExceptionHandler
OAuth2ExceptionRenderer
我们实施了
@ControllerAdvice @RestController public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
因此,只要资源服务器上出现错误,我们都希望它回答
{ "message": "...", "type": "...", "status": 400 }
资源服务器使用application.properties设置:
security.oauth2.resource.userInfoUri: http://localhost:9999/auth/user
对我们的身份验证服务器进行身份验证和授权请求。
但是,任何spring安全错误将始终绕过我们的异常处理程序
@ExceptionHandler(InvalidTokenException.class) public ResponseEntity<Map<String, Object>> handleInvalidTokenException(InvalidTokenException e) { return createErrorResponseAndLog(e, 401); }
并产生
{ "timestamp": "2016-12-14T10:40:34.122Z", "status": 403, "error": "Forbidden", "message": "Access Denied", "path": "/api/templates/585004226f793042a094d3a9/schema" }
要么
{ "error": "invalid_token", "error_description": "5d7e4ab5-4a88-4571-b4a4-042bce0a076b" }
那么,如何为资源服务器配置安全异常处理?我所发现的都是有关如何通过实现custom来定制Auth Server的示例OAuth2ExceptionRenderer。但是我找不到将其连接到资源服务器安全链的位置。
我们唯一的配置/设置是这样的:
@SpringBootApplication @Configuration @ComponentScan(basePackages = {"our.packages"}) @EnableAutoConfiguration @EnableResourceServer
如前面的注释中所述,该请求在到达MVC层之前被安全框架拒绝,因此@ControllerAdvice这里不是一个选择。
@ControllerAdvice
Spring Security框架中有3个接口可能是您感兴趣的:
您可以为每个接口创建实现,以自定义针对各种事件发送的响应:成功登录,登录失败,尝试使用权限不足访问受保护的资源。
以下将在登录尝试失败时返回JSON响应:
@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<String, Object> 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(); } }
您还需要向安全框架注册您的实现。在Java配置中,如下所示:
@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(); } }