로그아웃 logout()

정민교·2024년 7월 14일
0

spring security

목록 보기
8/13
post-thumbnail

📒목표

logout 필터 프로세스를 살펴보고 이해해보자.

📒개요

✔️로그아웃

  • 스프링 시큐리티는 formLogin 기능을 활성화 하는 경우 기본적으로 로그인/로그아웃 페이지를 제공한다.

  • 로그아웃 페이지는 DefaultLougoutPageGeneratingFilter를 통해 생성되고 "GET /logout" URL로 접근 가능하다.

  • 로그인 페이지는 DefautlLoginPageGeneratingFilter를 통해 생성되고 "GET /login" URL로 접근 가능하다.

  • 로그아웃 요청은 기본적으로 "POST /logout" URL로만 가능하지만, CSRF 기능을 비활성화 하는 경우 or RequestMatcher를 사용할 경우 GET, PUT, DELETE 모두 가능하다.

  • 로그아웃 필터(LogoutFilter)를 거치지 않고 스프링 MVC에서 커스텀으로 구현 가능하다

  • 로그인 페이지를 커스텀하여 생성하는 경우 로그아웃 기능도 커스텀으로 구현해야 한다.

✔️logout() API

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.logout(
                httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer
                        //로그아웃 요청이 수행될 URL을 지정한다(기본값은 "/logout")
                        .logoutUrl("/logoutProc")
                        //로그아웃 요청이 수행될 URL을 지정한다. httpMethod를 지정하지 않으면 모든 HTTP 메소드 요청으로 로그아웃 수행이 가능하다.
                        //logoutUrl api보다 우선순위가 높다
                        .logoutRequestMatcher(
                                new AntPathRequestMatcher("/logoutProc", "POST")
                        )
                        //로그아웃 완료된 후 redirect될 URL을 지정한다(기본값은 "/login?logout")
                        .logoutSuccessUrl("/logoutSuccess")
                        //로그아웃이 성공했을 떄 수행할 handler를 설정한다.
                        //이 handler를 지정하면, logoutSuccessUrl api 설정이 무시된다.
                        .logoutSuccessHandler((request, response, authentication) -> {
                            response.sendRedirect("/logoutSuccess");
                        })
                        //로그아웃 성공 시 제거될 쿠키의 이름을 지정할 수 있다.
                        .deleteCookies("JSESSIONID", "CUSTOM_COOKIE")
                        //HttpSession을 무효화한다. 기본값은 true
                        .invalidateHttpSession(true)
                        //로그아웃 시 SecurityContextLogoutHandler가 Authentication을 삭제한다. 기본값은 true
                        .clearAuthentication(true)
                        //기존 로그아웃 핸들러들 뒤에 새로운 `LogoutHandler`를 추가한다.
                        .addLogoutHandler(((request, response, authentication) -> {
                        }))
                        //logoutUrl(), RequestMatcher() URL에 대한 모든 사용자의 접근을 허용한다ㅣ.
                        .permitAll()
        );
        return http.build();
    }

✔️LogoutFilter의 간단 흐름

  1. 사용자가 로그아웃 요청을 한다.

  2. RequestMatcher를 통해 LogoutFilter가 동작해야 하는지 판단한다.

  3. RequestMatcher에 매칭되면, LogoutHandler가 동작한다.

    1. 스프링 시큐리티가 가지고 있는 기본적인 LogoutHandler들이 존재한다.
    2. 앞서 말했듯 추가로 우리가 정의한 LogoutHandler를 추가할 수 있다.(대체 X)
  4. 로그아웃이 성공하면 LogoutSuccessHandler가 동작한다. 우리가 정의한 LogoutSuccessHandler로 대체할 수 있다.

📒전반적인 실행 흐름 파악

처음 요청은 우선 FilterChainProxy가 받게 된다.

FilterChainProxy에서 SecurityFilterChain이 가지고 있는 Filter들을 순회하며 요청을 처리한다.

LogoutFilter 순서에 도달하면 현재 요청이 이 필터를 타야하는지 먼저 검증한다.

RequestMatcher와 일치하면 로그아웃 필터의 로직을 실행하게 된다.

SecurityContextHolder에서 SecurityContext를 꺼내고 Authentication 객체를 꺼낸다.

그리고 handler.logout을 실행하게 되는데 this.handlerCompositeLogoutHandler로 logoutHandler들의 목록을 가지고 있다.

여기서 두 번째 핸들러가 우리가 추가한 LogoutHandler다.

이제 각각의 로그아웃 핸들러들을 순회하며 logout을 호출하는데, 우리가 설정한 handler를 실행할 차례가 오면 해당 handler의 logout을 호출하게 된다.

커스텀하게 구현한 로그아웃 필터 내용은 기본적으로 스프링 시큐리티가 들고있는 로그아웃 핸들러 목록 중 SecurityContextLogoutHandler가 하는 내용을 간단하게 작성한 것이다.

profile
백엔드 개발자

0개의 댓글