1. ホーム
  2. spring

[解決済み] Springのセキュリティ認証の例外を@ExceptionHandlerで処理する

2022-07-30 18:56:15

質問

私はSpring MVCの @ControllerAdvice@ExceptionHandler で、REST Api のすべての例外を処理します。web mvc のコントローラからスローされる例外については問題なく動作しますが、 Spring security のカスタムフィルタからスローされる例外については、コントローラのメソッドが呼び出される前に実行されるため、動作しません。

私はトークンベースの認証を行うカスタムSpring Securityフィルターを持っています。

public class AegisAuthenticationFilter extends GenericFilterBean {

...

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        try {

            ...         
        } catch(AuthenticationException authenticationException) {

            SecurityContextHolder.clearContext();
            authenticationEntryPoint.commence(request, response, authenticationException);

        }

    }

}

このカスタムエントリーポイントで

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{

    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
    }

}

そして、このクラスでグローバルに例外を処理する。

@ControllerAdvice
public class RestEntityResponseExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler({ InvalidTokenException.class, AuthenticationException.class })
    @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public RestError handleAuthenticationException(Exception ex) {

        int errorCode = AegisErrorCode.GenericAuthenticationError;
        if(ex instanceof AegisException) {
            errorCode = ((AegisException)ex).getCode();
        }

        RestError re = new RestError(
            HttpStatus.UNAUTHORIZED,
            errorCode, 
            "...",
            ex.getMessage());

        return re;
    }
}

spring securityのAuthenticationExceptionでも詳細なJSONボディを返したいのですが、どうすればいいでしょうか?spring securityのAuthenticationEntryPointとspring mvcの@ExceptionHandlerを連携させる方法はないでしょうか?

spring security 3.1.4とspring mvc 3.2.4を使っています。

どのように解決するのですか?

OK、私は提案されたようにAuthenticationEntryPointから自分でjsonを書くことを試みました、それは動作します。

テストのために、私はAutenticationEntryPointをresponse.sendErrorを削除して変更しました。

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{

    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
    
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getOutputStream().println("{ \"error\": \"" + authenticationException.getMessage() + "\" }");

    }
}

このようにすると、Spring Security AuthenticationEntryPointを使用している場合でも、401の無承認と一緒にカスタムjsonデータを送信することができます。

もちろん、テスト用に私が行ったようにjsonをビルドするのではなく、何らかのクラスインスタンスをシリアライズすることになるでしょう。

Spring Bootでは、SecurityConfigurationファイルのhttp.authenticationEntryPoint()の部分に追加する必要があります。