REST 서비스를 개발 중입니다. JSON을 사용하며 문제가 발생하면 미리 정의 된 JSON 객체를 반환해야합니다. 기본 봄 응답은 다음과 같습니다스프링 MVC (또는 스프링 부트). 401 Unauthorized 또는 403 Forbidden과 같은 보안 관련 예외에 대한 사용자 정의 JSON 응답
{
"timestamp": 1512578593776,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/swagger-ui.html"
}
내가 (A 스택 트레이스 및 추가 예외 관련 정보)를 자신의 하나이 기본 JSON을 대체합니다.
스프링은 기본 동작을 덮어 쓸 수있는 편리한 방법을 제공합니다. 사용자 정의 예외 핸들러를 사용하여 @RestControllerAdvice
bean을 정의해야합니다. 이
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = {Exception.class})
public ResponseEntity<ExceptionResponse> unknownException(Exception ex) {
ExceptionResponse resp = new ExceptionResponse(ex, level); // my custom response object
return new ResponseEntity<ExceptionResponse>(resp, resp.getStatus());
}
@ExceptionHandler(value = {AuthenticationException.class})
public ResponseEntity<ExceptionResponse> authenticationException(AuthenticationExceptionex) {
// WON'T WORK
}
}
사용자 정의처럼 ExceptionResponse
객체는 특별한 메시지 변환기를 사용하여 Spring에 의해 JSON으로 변환됩니다.
문제 IS, InsufficientAuthenticationException
등이 보안 예외 @ExceptionHandler
같이 주석의 방법에 의해 차단 될 수 없다. 이러한 종류의 예외는 Spring MVC 디스패처 서블릿이 입력되고 모든 MVC 핸들러가 초기화되기 전에 발생합니다.
사용자 지정 필터를 사용하여이 예외를 가로 채고 자체 JSON 직렬화를 처음부터 만들 수 있습니다. 이 경우 스프링 MVC 인프라의 나머지 부분과 완전히 독립적 인 코드를 얻을 수있다. 이거는 좋지 않습니다.
내가 찾은 해결책은 효과가있는 것 같지만 미친 것처럼 보입니다.
@Configuration
public class CustomSecurityConfiguration extends
WebSecurityConfigurerAdapter {
@Autowired
protected RequestMappingHandlerAdapter requestMappingHandlerAdapter;
@Autowired
protected GlobalExceptionHandler exceptionHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.fullyAuthenticated();
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint());
}
public AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
try {
ResponseEntity<ExceptionResponse> objResponse = exceptionHandler.authenticationException(authException);
Method unknownException = exceptionHandler.getClass().getMethod("authenticationException", AuthenticationException.class);
HandlerMethod handlerMethod = new HandlerMethod(exceptionHandler, unknownException);
MethodParameter returnType = handlerMethod.getReturnValueType(objResponse);
ModelAndViewContainer mvc = new ModelAndViewContainer(); // not really used here.
List<HttpMessageConverter<?>> mconverters = requestMappingHandlerAdapter.getMessageConverters();
DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response);
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(mconverters);
processor.handleReturnValue(objResponse, returnType, mvc, webRequest);
} catch (IOException e) {
throw e;
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new ServletException(e);
}
}
};
}
이보다 더 나은 모습 (메시지 컨버터에서 MIME 형식 협상 등을 구축 봄과) 봄 직렬화 파이프를 사용하는 방법이 있나요?
여기 좀 더 우아한 해결책이 있지만, 원래 예외를 @ExceptionHandler가 "catch"할 수있는 예외로 래핑하는 것과 같습니다. https://stackoverflow.com/questions/43632565/exceptionhandler-for- a-pre-controller-filter-spring-security/43636386 – spekdrum
http://www.baeldung.com/spring-security-custom-access-denied-page –