私はRESTサービスを開発中です。 JSONを使用し、問題が発生した場合に事前定義されたJSONオブジェクトを返す必要があります。デフォルトの春の応答は次のようになります。Spring MVC(またはSpring Boot)。 401 Unauthorizedや403 Forbiddenなどのセキュリティ関連の例外に対するカスタムJSONレスポンス
{
"timestamp": 1512578593776,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/swagger-ui.html"
}
は、私が(スタックトレースと追加例外関連の情報を持つ)自分のものにこのデフォルトJSONを交換したいです。
Springでは、デフォルトの動作を上書きする便利な方法が提供されています。カスタム例外ハンドラを使用して@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
オブジェクトは、特別なメッセージコンバータを使って春のことでJSONに変換されます。
課題はInsufficientAuthenticationException
ようなセキュリティ例外が@ExceptionHandler
と注釈方法によって遮断することができないこと、です。この種の例外は、Spring MVCディスパッチャーサーブレットが入力され、すべてのMVCハンドラーが初期化される前に発生します。
カスタムフィルタを使用してこの例外を傍受し、独自のJSON直列化を最初から構築することは可能です。この場合、Spring 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によって「キャッチされる」例外にラップします: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 –