2017-12-06 15 views
8

私は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形式の交渉などを構築春に)春のシリアライズパイプを使用する方法はありますか?

+0

ここにもう少し洗練されたソリューションがありますが、あなたのようなものですが、元の例外を@ExceptionHandlerによって「キャッチされる」例外にラップします:https://stackoverflow.com/questions/43632565/exceptionhandler-for- a-pre-controller-filter-spring-security/43636386 – spekdrum

+0

http://www.baeldung.com/spring-security-custom-access-denied-page –

答えて

0

春は、以下のようなカスタムハンドラ何かを実装AccessDeniedExceptionすなわち​​

の場合のカスタムJSONレスポンスを実現するための手順の下に、以下により利用することができAccessDeniedHandlerを経由して、例外処理のためのアウトオブボックスのサポートを提供します/denyを除外するために確保-

public class CustomAccessDeniedHandler implements AccessDeniedHandler { 

    @Override 
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exc) 
     throws IOException, ServletException { 
     System.out.println("Access denied .. "); 
     // do something 
     response.sendRedirect("/deny"); 
    } 
} 

次は重要な注意(を設定して、このハンドラのBeanを作成し、セキュリティ例外ハンドラを春にそれを供給します他の認証からの要求が無限に/denyに対応するハンドラを記述し、単にSomeExceptionまたは適しなどの他のExceptionの新しいインスタンスを投げるコントローラクラスに次の

@Bean 
public AccessDeniedHandler accessDeniedHandler(){ 
    return new CustomAccessDeniedHandler(); 
} 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.cors().and() 
      // some other configuration 
      .antMatchers("/deny").permitAll() 
      .and() 
      .exceptionHandling().accessDeniedHandler(accessDeniedHandler()); 
} 

)エラーを解決する上で維持されます)どの意志それぞれのハンドラの@RestControllerAdviceで傍受される。

@GetMapping("/deny") 
public void accessDenied(){ 
    throw new SomeException("User is not authorized"); 
} 

これ以上の情報が必要な場合は、コメントでお知らせください。

0

次の設定がうまくいくと思います。試してみてください。

@Autowired 
private HandlerExceptionResolver handlerExceptionResolver; 

public AuthenticationEntryPoint authenticationEntryPoint() { 
    return new AuthenticationEntryPoint() { 
     @Override 
     public void commence(HttpServletRequest request, HttpServletResponse response, 
          AuthenticationException authException) throws IOException, ServletException { 

      try { 
       handlerExceptionResolver.resolveException(request, response, null, authException); 
      } catch (RuntimeException e) { 
       throw e; 
      } catch (Exception e) { 
       throw new ServletException(e); 
      } 
     } 
    }; 
} 
1

Beanクラス

@Component public class AuthenticationExceptionHandler implements AuthenticationEntryPoint, Serializable 

を作成し、commence() methodをオーバーライドし、SecurityConfigurationクラスの例以下

ObjectMapper mapper = new ObjectMapper(); 
String responseMsg = mapper.writeValueAsString(responseObject); 
response.getWriter().write(responseMsg); 

@Autowire AuthenticationExcetionHandlerのようなオブジェクトマッパーを使用してJSONレスポンスを作成し、configure(HttpSecurity http) methodにライン

の下に追加
 http.exceptionHandling() 
      .authenticationEntryPoint(authenticationExceptionHandler) 

このようにすれば、あなたはカストムのjsonレスポンス401/403を送ることができます。上記と同じですAccessDeniedHandlerを使用することができます。これが問題の解決に役立ったかどうかをお知らせください。

関連する問題