Spring Security

[Spring Security] logout

yoongeon 2024. 5. 12. 19:51

Spring Security는 기본적으로 DefaultLogoutPageGeneratingFilter를 통해 로그아웃 페이지를 제공하며 GET /logout으로 접근이 가능하다.

 

로그아웃 실행은 기본적으로 POST /logout으로만 가능하며 csrf 기능을 비활성화 할 경우 또는 RequestMatcher 를 사용할 경우 GET, PUT, DELETE 모두 가능하다.

 

로그아웃 필터를 거치지 않고 MVC에서 커스텀으로 구현할 수 있으며, 로그인 페이지를 커스텀으로 구현했을 경우 로그아웃 또한 커스텀으로 구현해야 한다.

 

아래는 logout config 설정들이다.

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http.authorizeHttpRequests(auth -> auth
                .requestMatchers("/logoutSuccess").permitAll()
                .anyRequest().authenticated());

        http.formLogin(Customizer.withDefaults());

        http.logout(logout -> logout
                .logoutUrl("/logout")   // 로그아웃이 발생하는 URL지정 (default : /logout)
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "POST")) // logoutUrl과 logoutRequestMatcher가 둘다 설정되어있을경우 RequestMatcher가 우선적으로 실행된다.
                .logoutSuccessUrl("/logoutSuccess") // 로그아웃이 된 후 리다이렉트가 될 URL지정 (default: /login?logout)
                .logoutSuccessHandler(new LogoutSuccessHandler() {  // 사용할 logout handler를 설정한다. handler는 위에서 한 설정보다 우선적으로 실행된다.
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.sendRedirect("/logoutSuccess");    // 이렇게 되면 위에서 설정한 logoutSuccessUrl은 적용되지 않는다.
                    }
                })
                .deleteCookies("JSESSIONID", "remember-me") // 로그아웃 시 삭제할 쿠키를 지정할 수 있다.
                .invalidateHttpSession(true)    // HttpSession을 무효화 한다. (default : true)
                .clearAuthentication(true)  // 로그아웃 시 SecurityContextLogoutHandler가 인증객체(Authentication)을 삭제한다.
                .addLogoutHandler(new LogoutHandler() {
                    @Override
                    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
                        HttpSession session = request.getSession();
                        session.invalidate();
                        SecurityContextHolder.getContextHolderStrategy().getContext().setAuthentication(null);  // security context에 저장된 authentication 객체를 없앤다.
                        SecurityContextHolder.getContextHolderStrategy().clearContext();    // security context 초기화를 한다.
                    }
                })
                .permitAll()); // logoutUrl(), RequestMatcher()의 URL에 대한 모든 접근을 허용한다.

        return http.build();
    }

 

로그아웃 할때 별다른 커스텀 기능이 없다면 따로 설정을 할 필요는 거의 없다. 만약 필요하다면 위와같은 설정들을 해주면 된다.

📌 logoutSuccessHandler

이 핸들러는 이름에서도 알 수 있듯이 logout을 성공하게 되면 실행되는 핸들러이다. 위에서는 로그아웃 시 /logoutSuccess로 리다이렉트 하도록 설정이 했다.

(주의할점은 로그아웃을 할 경우 인증 상태가 사라지기 때문에 http.anyRequest().authenticaiton() 설정으로 인해 페이지 이동이 정상적을 안될 수 있다. 그래서 http.requestMatcher("logoutSuccess").permitAll() 설정을 따로 해주었다.)

📌 addLogoutHandler

설정 중 addLogoutHandler 설정이 있는데, 로그아웃을 할 때 Spring Security 내부적으로 동작하는 핸들러가 몇가지 있다. 그 핸들러들이 실행될 때 추가적으로 커스텀하여 실행시킬 수 있는 설정이다.

위의 코드에서는 로그아웃을 하게 되면 security context에서 authentication 객체를 삭제하고 security context를 초기화하는 코드를 넣었는데 이 작업은 원래 동작하는 핸들러중 SecurityContextLogoutHandler라는 핸들러에서 실행되는 코드임으로 따로 작성은 불필요하다. (위에서는 그냥 예시를 위해 작성한 코드이다.)