[Spring Security] 인증/인가의 Exception

SeongWon Oh·2022년 1월 4일
0

Spring Framework

목록 보기
32/33
post-thumbnail
post-custom-banner

인증/인가 예외의 큰그림

Spring Security에서 인증/인가에 대한 예외처리는 FilterSecurityFilterExceptionTranslationFilter가 처리를 하게 됩니다. 해당 필터는 크게 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

AuthenticationException은 인증에 문제가 생길 때 발생하는 exception입니다. 해당 exception을 처리하는 방법은 다음과 같이 2 step이 있습니다.

Step1. AuthenticationEntryPoint 호출하기

  • AuthenticationEntryPoint은 인터페이스로 Spring Security에서 제공하는 AuthenticationEntryPoint인터페이스를 구현한 구현체를 호출해줍니다.
  • 이를 호출함으로써 로그인페이지로 이동, 401 오류 전달 등의 작업을 해줍니다.

Step2. 인증 예외가 발생하기 전의 요청 정보를 저장한다.

  • Ex) 웹서핑들을 하며 특정 페이지를 이동하려했는데 해당 페이지는 인증이 필요하여 이동하려던 페이지가 아닌 로그인 페이지로 이동하게 된 경험을 모두들 해보셨을 겁니다. 주로 이때 로그인을 하게 되면 초기 페이지가 아닌 이전에 요청하였던 페이지로 이동하게 될 겁니다.

  • 이렇게 예외가 발생하기 전 원래 이동하고자 하였던 페이지 요청 정보를 저장하고 로그인 후에 해당 페이지로 이동하게 하기 위해 요청 정보 저장을 합니다.

  • 요청정보 저장을 할 때는 RequestCacheSavedRequest를 사용합니다.

    • RequestCache : 사용자의 이전 요청 정보를 세션에 저장하고 꺼내오는 일을 한다.
    • SavedRequest : 사용자가 요청하였던 요청의 파라미터 값과 header값을 저장합니다.
    • 즉, 요청 정보를 실제로 저장하는 것은 SavedRequest 구현체가 수행하며 이를 세션에 저장하는 것은 RequestCache인터페이스의 구현체가 수행합니다.
  • AuthenticationException을 처리할 때는 authenticationEntryPoint를 사용하며 commence를 재정의하여 사용하여야 합니다.

AccessDeniedException

AccessDeniedException은 권한이 없는 데이터에 접속을 하려고 하였을 때 발생하는 exception입니다.

이는 AccessDeniedHandler에서 처리를 해줍니다.
AccessDeniedHandler를 사용할 때는 handle을 재정의하여 사용해야합니다.

AuthenticationException, AccessDeniedException을 적용한 예시 코드

    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");
                    }
                });
    }

Reference

해당 인프런 강의를 수강하며 이해한 내용들을 정리하였습니다. 문제가 될 시 삭제하겠습니다.

profile
블로그 이전했습니다. -> https://seongwon.dev/
post-custom-banner

0개의 댓글