본문 바로가기

Language/Spring Security

로그 아웃 -­ logout()

  • 스프링 시큐리티는 기본적으로 DefaultLogoutPageGeneratingFilter 를 통해 로그아웃 페이지를 제공
    → “ GET / logout ” URL로 접근 가능
    • 폼 로그인 사용 시 DefaultLoginPageGeneratingFilter, DefaultLogoutPageGeneratingFilter 두 개가 자동 생성
  • 로그아웃 실행은 기본적으로 “ POST / logout “으로만 가능하나 CSRF 기능을 비활성화 또는 RequestMatcher 사용 시 GET, PUT, DELETE 모두 가능
    • CSRF : 누군가가 사용자의 세션을 가지고 악의적인 목적으로 사용하는 것을 막기 위한 보안 기술(?)
  • 로그아웃 필터를 거치지 않고 스프링 MVC 에서 커스텀 하게 구현할 수 있으며, 로그인 페이지가 커스텀하게 생성될 경우 로그아웃 기능도 커스텀하게 구현
    • 로그인과 로그아웃은 세트이기 때문에 로그인 페이지가 커스텀하게 생성될 경우 로그아웃 기능도 커스텀하게 구현 필요

logout() API

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/logoutSuccess").permitAll()
                    .anyRequest().authenticated())
            .formLogin(Customizer.withDefaults())
            .logout(logout -> logout
                    .logoutUrl("/logoutProc")
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logoutProc","POST"))
                    .logoutSuccessUrl("/logoutSuccess")
                    .logoutSuccessHandler((request, response, authentication) -> {
                        response.sendRedirect("/logoutSuccess");
                    })
                    .deleteCookies("JSESSIONID", "CUSTOM_COOKIE")
                    .invalidateHttpSession(true)
                    .clearAuthentication(true)
                    .addLogoutHandler((request, response, authentication) -> {})
                    .permitAll()
            )
    ;
    return http.build();
}
Method Description
.logoutUrl("/logoutProc") 로그아웃이 발생하는 URL 지정 (기본값 /logout)
→ form action과 동기화
.logoutRequestMatcher(new AntPathRequestMatcher("/logoutProc","POST")) 로그아웃이 발생하는 RequestMatcher 지정, logoutUrl보다 우선
→ Http Method(GET,POST 등)를 지정하지 않을 경우 어떤 메소드든 로그아웃 가능
.logoutSuccessUrl("/logoutSuccess") 로그아웃 성공 후 리다이렉션 될 URL 지정 (기본값 /login?logout)
.logoutSuccessHandler(logoutSuccessHandler) 사용할 LogoutSuccessHandler 지정
→ 지정 시 logoutSuccessUrl 무시
.deleteCookies("JSESSIONID“, “CUSTOM_COOKIE”) 로그아웃 성공 시 제거할 쿠키의 이름 지정
.invalidateHttpSession(true) HttpSession 무효화 (기본값 true)
.clearAuthentication(true) 로그아웃 시 SecurityContextLogoutHandler가 인증(Authentication)을 삭제해야하는 지 여부를 명시
.addLogoutHandler(logoutHandler) 기존의 로그아웃 핸들러 뒤에 새로운 LogoutHandler 추가
→ 사용자 정의 핸들러를 추가할 경우 기존 LogoutHandler가 대체 되는 것이 아니라 기존 것이 수행된 후 사용자 정의 LogoutHandler 실행
.permitAll() logoutUrl(), RequestMathcher()의 URL에 대한 모든 사용자 접근 허용

 

LogoutFilter

  1. 클라이언트가 로그아웃 버튼 클릭
  2. LogoutFilter 수신
  3. RequestMatcher → 요청 정보가 매칭 되는 지 확인(POST 방식인지, /logout인지)
    • 매칭되지 않을 경우 다음 필터(chain.doFilter)
  4. LogoutHandler → 다음 여러 개의 핸들러 실행
    • CookieClearingLogoutHandler
    • SecurityConfig → 개발자가 생성한 설정 클래스
    • CsrfLogoutHandler
    • SecurityContextLogoutHandler
    • LogoutSuccessEventPublishingLogoutHandler
  5. LogoutSucessHandler → 어디로 이동할 것인지 URL을 지정
    • 기본값 : /login?logout

정리

  • 기본 제공 로그아웃은 POST 방식으로 /logout 이지만, RequestMatcher 사용 또는 csrf 미 사용(disable) 시 GET, PUT, DELETE 방식으로도 로그아웃 가능
  • 로그인과 로그아웃은 한 세트이기 때문에 사용자 정의 로그인 페이지를 사용할 경우, 로그 아웃도 구현 필요
  • 로그아웃 성공 후 단순히 URL만 이동시킬 목적이라면 .logoutSuccessUrl() 메서드를 사용하고, HttpServletRequest / HttpServletResponse 등의 사용이 필요하다면 .logoutSuccessHandler() 메서드 사용