Spring Security에서 인증/인가에 대한 예외처리는 FilterSecurityFilter와 ExceptionTranslationFilter가 처리를 하게 됩니다. 해당 필터는 크게 AuthenticationException(인증 예외)과 AccessDeniedException(인가 예외)을 처리를 합니다. 해당 Exception들은 필터들 중 가장 마지막에 위치한 FilterSecurityFilter에서 발견을 하게 되는데 FilterSecurityFilter는 앞에 위치한 ExceptionTranslationFilter에서 try/catch로 해당 exception들을 받기 위해 FilterSecurityFilter를 호출하여 사용하게 됩니다.
FilterSecurityFilter에서 발생하는 인증/인가 예외는 FilterSecurityFilter를 호출한 ExceptionTranslationFilter에게로 인증/인가 예외를 throw하고 ExceptionTranslationFilter는 throw받은 인증/인가 예외를 처리하는 일을 합니다.
즉, 간단하게 설명하자면 인증/인가의 exception은 AccessDeniedException과 AuthenticationException이 존재한다. 이를 처리하는데 사용되는 필터는 FilterSecurityFilter와 ExceptionTranslationFilter가 존재하는데 동작은 ExceptionTranslationFilter가 try/catch를 통해 exception을 발견하는 FilterSecurityFilter를 호출하고 발생한 exception을 처리하게 됩니다.
AuthenticationException은 인증에 문제가 생길 때 발생하는 exception입니다. 해당 exception을 처리하는 방법은 다음과 같이 2 step이 있습니다.
Step1. AuthenticationEntryPoint 호출하기
Step2. 인증 예외가 발생하기 전의 요청 정보를 저장한다.
Ex) 웹서핑들을 하며 특정 페이지를 이동하려했는데 해당 페이지는 인증이 필요하여 이동하려던 페이지가 아닌 로그인 페이지로 이동하게 된 경험을 모두들 해보셨을 겁니다. 주로 이때 로그인을 하게 되면 초기 페이지가 아닌 이전에 요청하였던 페이지로 이동하게 될 겁니다.
이렇게 예외가 발생하기 전 원래 이동하고자 하였던 페이지 요청 정보를 저장하고 로그인 후에 해당 페이지로 이동하게 하기 위해 요청 정보 저장을 합니다.
요청정보 저장을 할 때는 RequestCache
와 SavedRequest
를 사용합니다.
RequestCache
: 사용자의 이전 요청 정보를 세션에 저장하고 꺼내오는 일을 한다.SavedRequest
: 사용자가 요청하였던 요청의 파라미터 값과 header값을 저장합니다.AuthenticationException을 처리할 때는 authenticationEntryPoint
를 사용하며 commence
를 재정의하여 사용하여야 합니다.
AccessDeniedException은 권한이 없는 데이터에 접속을 하려고 하였을 때 발생하는 exception입니다.
이는 AccessDeniedHandler
에서 처리를 해줍니다.
AccessDeniedHandler
를 사용할 때는 handle
을 재정의하여 사용해야합니다.
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.successHandler(
new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// 해당 객체에 이전에 요청받은 url정보를 세션에 저장하고 인증이 된다면 해당 url로 이동하게 설정
RequestCache requestCache = new HttpSessionRequestCache();
SavedRequest savedRequest = requestCache.getRequest(request, response);
String redirectUrl = savedRequest.getRedirectUrl();
response.sendRedirect(redirectUrl);
}
}
);
http
.exceptionHandling()
.authenticationEntryPoint(new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendRedirect("/login");
}
})
.accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendRedirect("/denied");
}
});
}
해당 인프런 강의를 수강하며 이해한 내용들을 정리하였습니다. 문제가 될 시 삭제하겠습니다.