私は Spring MVC を使用して@ControllerAdvice
、@ExceptionHandler
REST API のすべての例外を処理しています。Web MVC コントローラーによってスローされた例外に対しては正常に機能しますが、コントローラー メソッドが呼び出される前に実行されるため、Spring Security カスタム フィルターによってスローされた例外に対しては機能しません。
トークンベースの認証を行うカスタム Spring セキュリティ フィルターがあります。
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 を使用しています。
ベストアンサー1
わかりました。提案されたとおりに、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() 部分に追加する必要があります。