Spring Security Logout

✒️ 2025-07-02 11:27 내용 수정



Logout 구조

GET /logout

spring_security_logout 1.png

POST /logout

  1. POST /logout 요청을 전송한다.
  2. LogoutFilter가 요청을 가로채어 LogoutHandler를 호출한다.
  3. SecurityContextLogoutHandler가 로그아웃과 연관된 객체 등을 정리한다.
    1. HTTP Session을 만료 시킨다. 쿠키도 설정에 따라 함께 제거할 수 있다.
    2. SecurityContextHolderStrategy를 비운다.
    3. SecurityContextRepository를 비운다.
  4. TokenRememberMeServicesPersistentTokenRememberMeServices에서 RememberMe authentication을 비운다.
  5. CsrfLogoutHandler에서 저장된 CSRF Token을 제거한다.
  6. LogoutSuccessEventPublishingLogoutHandler에서 LogoutSuccessEvent를 내보낸다.
  7. 기본 LogoutSuccessHandler/login?logout으로 리다이렉트 시킨다.

커스텀 Logout URI 설정

public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
	http
	    .logout((logout) -> logout.logoutUrl("/my/logout/uri"));

	// ...
}
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
	http
	    .authorizeHttpRequests((authorize) -> authorize
		    // 커스텀 endpoint를 허용하도록 설정
	        .requestMatchers("/my/success/endpoint").permitAll()
	        // ...
	    )
	
		// 커스텀 logout 성공 endpoint 설정
	    .logout((logout) -> logout.logoutSuccessUrl("/my/success/endpoint"));
	    // ...
}
// Java configuration 사용 시
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
	http
	    .authorizeHttpRequests((authorize) -> authorize
	        // ...
	    )
	
		// 커스텀 logout 성공 endpoint 설정하고 허용
	    .logout((logout) -> logout
			    .logoutSuccessUrl("/my/success/endpoint")
			    .permitAll()
		);
	    // ...
}
public class DemoController {
	// LogoutHandler 생성
	SecurityContextLogoutHandler logoutHandler 
		= new SecurityContextLogoutHandler();
	
	@PostMapping("/my/logout") 
	public String performLogout(
		Authentication authentication, 
		HttpServletRequest request, 
		HttpServletResponse response
	) { 
		// .. logout 수행
		this.logoutHandler
			.doLogout(
				request, 
				response, 
				authentication
			); 
		return "redirect:/home"; 
	}
}

Clean-up action 추가

// Java configuration 사용 시
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
	// 쿠키 제거 LogoutHandler
	CookieClearingLogoutHandler cookies = new CookieClearingLogoutHandler("custom-cookie");
	
	http
	    .authorizeHttpRequests((authorize) -> authorize
	        // ...
	    )
	
		// 쿠키를 비우는 LogoutHandler 추가
	    .logout((logout) -> logout
			    .addLogoutHandler(cookies)
		);
	    // ...
}
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
	http
	    .authorizeHttpRequests((authorize) -> authorize
	        // ...
	    )
	
		// 특정 쿠키 제거
	    .logout((logout) -> logout
			    .deleteCookies("custom-cookie")
		);
	    // ...
}
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
	http
	    .authorizeHttpRequests((authorize) -> authorize
	        // ...
	    )
	
		// 특정 쿠키 제거
	    .logout((logout) -> logout
			    .invalidateHttpSession(false)
			    .clearAuthentication(false)
		);
	    // ...
}
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
	// ClearSiteDataHeader를 작성하는 LogoutHandler 생성
	HeaderWriterLogoutHandler clearSiteData = 
		new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter());
	
	http
	    .authorizeHttpRequests((authorize) -> authorize
	        // ...
	    )
	
		// LogoutHanler 추가
	    .logout((logout) -> logout
			    .addLogoutHandler(clearSiteData)
		);
	    // ...
}
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
	// ClearSiteDataHeader를 작성하는 LogoutHandler 생성 - cookie만 제거
	HeaderWriterLogoutHandler clearSiteData = 
		new HeaderWriterLogoutHandler(
			new ClearSiteDataHeaderWriter(Directive.COOKIES)
		);
	
	http
	    .authorizeHttpRequests((authorize) -> authorize
	        // ...
	    )
	
		// LogoutHanler 추가
	    .logout((logout) -> logout
			    .addLogoutHandler(clearSiteData)
		);
	    // ...
}

Logout 성공 커스터마이징

public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
	http
	    .authorizeHttpRequests((authorize) -> authorize
	        // ...
	    )
	
		// status code를 반환하는 LogoutSuccessHandler 추가
	    .logout((logout) -> logout
			    .logoutSuccessHandler(
				    new HttpStatusReturningLogoutSuccessHandler()
				)
		);
	    // ...
}