[ODOP] 79 일차 - ExceptionTranslationFilter, RequestCacheAwareFilter

[ODOP] 79 일차 - ExceptionTranslationFilter, RequestCacheAwareFilter

ExceptionTranslationFilter

해당 Filter 는 FilterSecurityInterceptor 가 던지는 예외를 받아 처리하는 역할을 수행합니다

AuthenticationException

인증 예외 처리

  1. AuthenticationEntryPoint 호출 (인터페이스를 구현하면 기본 구현체를 대체 가능)
    - 로그인 페이지 이동, 401 오류 코드 전달 등
  2. 인증 예외가 발생하기 전의 요청 정보를 저장
    사용자가 요청한 reqeust 파라미터 값들을 저장하는 인터페이스 : SavedRequest
    SavedRequest 를 저장하는 인터페이스 : RequestCache
    - interface RequestCache: 사용자의 이전 요청 정보를 세션에 저장하고 이를 꺼내 오는 캐시 매커니즘
    - interface SavedRequest: 사용자가 요청했던 request 파라미터 값들, 그 당시의 헤더 값들 등이 저장

AccessDeniedException

인가 예외 처리

  • interface AccessDeniedHandler 에서 예외 처리하도록 제공

ExceptionTranslationFilter 프로세스

FilterSecurityInterceptor 는 Security 에 존재하는 Filter 중 제일 마지막으로 동작

유저가 익명사용자인 경우

  1. 유저가 /user 로의 접근을시도
    (로그인 시도 한 유저는 로그인을 하지 않은 익명 사용자)

    하지만 위 그림을 보면 이상한 부분이 있다
    맨 마지막에 동작하는 Filter 라면 이미 '익명사용자' 로 인증이 끝난 상태일 텐데 그림에는 인증 예외로 적혀 있다.
    사실 그런 경우에는 ExceptionTranslationFilter 가 AccessDeniedException 을 발생시키지만 실제 로직은 AuthenticationException 으로 빠지게 된다.

  2. 인증 예외가 발생
    AuthenticationEntryPoint 가 인증에 실패한 사용자를 login 페이지로 보낸다
    HttpSessionRequestCache 가 사용자의 정보를 저장
    해당 정보는 session 에 저장

유저의 권한이 부족한 경우

  1. 유저가 /user 로의 접근을 시도
    • 해당 유저는 로그인은 했으나 user 권한을 가지고있지 않은 사용자
  2. 인가 예외 발생 (AccessDeniedException)
    AccessDeniedHandler 가 해당 Exception 을 처리
    결과적으로 사용자를 /denied 으로 리다이렉트 시킨다.

설정

protected void configure(HttpSecurity http) throws Exception {
		http.exceptionHandling()
				.authenticationEntryPoint(authenticationEntryPoint()) // 인증 실패 시 처리
				.accessDeniedHandler(accessDeniedHandler());          // 인가 실패 시 처리
}

예제

private void authenticationConfigure(HttpSecurity http) throws Exception {
    http.exceptionHandling()
        .authenticationEntryPoint((request, response, authException) -> {
            response.sendRedirect("/login");
        })
        .accessDeniedHandler((request, response, accessDeniedException) -> {
            response.sendRedirect("/denied");
        })
    ;
}

여기서 redirect 되는 경로는 Spring Security 가 만들어주는 login 페이지가 아니라, 개발자가 만든 페이지로 이동하게 된다. 따라서 해당 화면을 만들어 주어야 한다