Обрабатывать исключения безопасности в Spring Boot Resource Server
как я могу получить мой заказ ResponseEntityExceptionHandler
или OAuth2ExceptionRenderer
обрабатывать исключения, вызванные Spring security на чистом сервере ресурсов?
мы реализовали
@ControllerAdvice
@RestController
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
поэтому всякий раз, когда есть ошибка на сервере ресурсов, мы хотим, чтобы он ответил с
{
"message": "...",
"type": "...",
"status": 400
}
сервер ресурсов использует приложение.настройка свойств:
security.oauth2.resource.userInfoUri: http://localhost:9999/auth/user
для аутентификации и авторизации запроса на нашем сервере аутентификации.
однако любая весна ошибка безопасности всегда будет обходить наш обработчик исключений в
@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"
}
Итак, как настроить обработку исключений безопасности для сервера ресурсов? Все, что я когда-либо находил, - это примеры того, как настроить сервер Auth, реализовав пользовательский OAuth2ExceptionRenderer
. Но я не могу найти, где подключить это к цепочке безопасности сервера ресурсов.
наша единственная конфигурация/настройки это:
@SpringBootApplication
@Configuration
@ComponentScan(basePackages = {"our.packages"})
@EnableAutoConfiguration
@EnableResourceServer
5 ответов
как отмечалось в предыдущих комментариях, запрос отклоняется платформой безопасности, прежде чем он достигнет уровня MVC so @ControllerAdvice
- это не вариант.
в Spring Security framework есть 3 интерфейса, которые могут представлять интерес здесь:
- org.springframework.безопасность.сеть.идентификация.AuthenticationSuccessHandler
- org.springframework.безопасность.сеть.идентификация.AuthenticationFailureHandler
- org.springframework.безопасность.сеть.доступ.AccessDeniedHandler
вы можете создавать реализации каждого из этих интерфейсов для настройки ответа, отправленного для различных событий: успешного входа в систему, неудачного входа в систему, попытки доступа к защищенному ресурсу с помощью недостаточные разрешения.
следующее вернет ответ 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();
}
}
в случае если вы используете @EnableResourceServer
, вы также можете найти удобным для расширения ResourceServerConfigurerAdapter
вместо WebSecurityConfigurerAdapter
в своем @Configuration
класса. Сделав это, вы можете просто зарегистрировать custom AuthenticationEntryPoint
переопределив configure(ResourceServerSecurityConfigurer resources)
и с помощью resources.authenticationEntryPoint(customAuthEntryPoint())
внутри метода.
что-то вроде этого:
@Configuration
@EnableResourceServer
public class CommonSecurityConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.authenticationEntryPoint(customAuthEntryPoint());
}
@Bean
public AuthenticationEntryPoint customAuthEntryPoint(){
return new AuthFailureHandler();
}
}
еще OAuth2AuthenticationEntryPoint
который может быть расширен (поскольку он не является окончательным) и частично повторно использован при реализации пользовательского AuthenticationEntryPoint
. В частности, он добавляет Заголовки "WWW-Authenticate" с деталями, связанными с ошибкой.
вы не можете использовать аннотации обработчика исключений Spring MVC, такие как @ControllerAdvice
потому что весенние фильтры безопасности срабатывают намного раньше весеннего MVC.
OAuth2ExceptionRenderer предназначен для сервера авторизации. Правильный ответ, вероятно, будет обрабатывать его, как подробно описано в этом посте (то есть игнорировать, что это oauth и относиться к нему как к любому другому механизму аутентификации spring security):https://stackoverflow.com/a/26502321/5639571
конечно, это поймает связанные с OAuth исключения (которые выбрасываются до достижения конечной точки ресурса), но любые исключения, происходящие в конечной точке ресурса, все равно будут требуется метод @ExceptionHandler.
Весна 3.0 вперед, вы можете использовать @ControllerAdvice
(на уровне класса) и распространяется org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
класс CustomGlobalExceptionHandler
@ExceptionHandler({com.test.CustomException1.class,com.test.CustomException2.class})
public final ResponseEntity<CustomErrorMessage> customExceptionHandler(RuntimeException ex){
return new ResponseEntity<CustomErrorMessage>(new CustomErrorMessage(false,ex.getMessage(),404),HttpStatus.BAD_REQUEST);
}