[์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ๊ธฐ๋ณธ API & Filter ์ดํ•ด] Logout & ํ•„ํ„ฐ

๐Ÿ“ ์ด ๊ธ€์€ ์ธํ”„๋Ÿฐ ์ธํ„ฐ๋„ท ๊ฐ•์˜ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ - Spring Boot ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ๋ฐœํ•˜๋Š” Spring Security ์—์„œ ๊ธฐ๋ฐ˜๋œ ๊ฒƒ์œผ๋กœ ์—ฌ๊ธฐ์„œ ์ธ์šฉ๋˜๋Š” PPT ์ด๋ฏธ์ง€ ๋˜ํ•œ ๋ชจ๋‘ ํ•ด๋‹น ๊ฐ•์˜์—์„œ ๊ฐ€์ ธ์™”์Œ์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.

 

๐Ÿ”น Logout ๋™์ž‘ ๋ฐฉ์‹

  • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ์„ ํ•œ๋‹ค.
  • Spring Security๊ฐ€ ๋กœ๊ทธ์•„์›ƒ์— ๋Œ€ํ•ด ํ•„์š”ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
    • ์„ธ์…˜ ๋ฌดํšจํ™”
    • ์ธ์ฆํ† ํฐ ์‚ญ์ œ
    • ์ธ์ฆํ† ํฐ์„ ๊ฐ–๊ณ  ์žˆ๋˜ SecurityContext ์‚ญ์ œ
    • ์ฟ ํ‚ค ์ •๋ณด ์‚ญ์ œ
    • ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
  • ์œ„ ๊ณผ์ •๋ฟ ์•„๋‹ˆ๋ผ ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ปค์Šคํ…€ํ•˜์—ฌ ๋กœ๊ทธ์•„์›ƒ ์ž‘์—…์„ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

๐Ÿ”น Logout API

Form Logout ์‚ฌ์šฉ์€ src > main > java > io > security > basicsecurity > SecurityConfig ์ž‘์„ฑํ•œ๋‹ค.

์‚ฌ์šฉ์€ http.formLogout()๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ์ด ์ž‘๋™ํ•˜๋ฉฐ, api๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	http.logout() // ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ ์ ์šฉ
		.logoutUrl("/logout") // ๋กœ๊ทธ์•„์›ƒ ์ฒ˜๋ฆฌ URL
		.logoutSuccessUrl("/login") // ๋กœ๊ทธ์•„์›ƒ ์„ฑ๊ณต ํ›„ ์ด๋™ํŽ˜์ด์ง€
		.deleteCookies("JSESSIONID", "remember-me") // ๋กœ๊ทธ์•„์›ƒ ํ›„ ์ฟ ํ‚ค ์‚ญ์ œ
		.addLogoutHandler(logoutHandler()) // ๋กœ๊ทธ์•„์›ƒ ํ•ธ๋“ค๋Ÿฌ
		.logoutSuccessHandler(logoutSuccessHandler()) // ๋กœ๊ทธ์•„์›ƒ ์„ฑ๊ณต ํ›„ ํ•ธ๋“ค๋Ÿฌ
}

 

๐Ÿ’ก ์‚ฌ์šฉ์˜ˆ์‹œ

// import ์ƒ๋žต

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    	http
    		.logout()
    		.logoutUrl("/logout")
    		// .logoutSuccessUrl("/login") // logoutSuccessHandler ๋Œ€์ฒด
    		.addLogoutHandler(new LogoutHandler() {
    			@Override
    			public void logout(HttpServletRequest request, 
    			HttpServletResponse response, Authentication authentication) {
    				HttpSession session = request.getSession();
    				session.invalidate();
    				// ์„ธ์…˜ ๋ฌดํšจํ™”, ์ง์ ‘ ํ•˜์ง€ ์•Š์•„๋„ LogoutFilter๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ํ•จ
    			}
    		})
    		.logoutSuccessHandler(new LogoutSuccessHandler() {
    			@Override
    			public void onLogoutSuccess(HttpServletRequest request, 
    			HttpServletResponse response, Authentication authentication) 
    			throws IOException, ServletException {
    				response.sendRedirect("/login");
    			}
    		})
    		.deleteCookies("remember-me"); // ๋กœ๊ทธ์•„์›ƒ ํ›„ ์‚ญ์ œํ•  ์ฟ ํ‚ค ์ง€์ •
    	return http.build();
    }
}
  • Logout ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๋ฉด LogoutFilter๊ฐ€ ์ƒ๊ธด๋‹ค.
  • ํ•ด๋‹น ํ•„ํ„ฐ ๋‚ด๋ถ€์—๋Š” ์ด๋ฏธ ์•„๋ž˜์™€ ๊ฐ™์€ ๋กœ๊ทธ์•„์›ƒ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์กด์žฌํ•œ๋‹ค.
    • ์„ธ์…˜ ๋ฌดํšจํ™” ํ•ธ๋“ค๋Ÿฌ
    • ์ธ์ฆ ํ† ํฐ, SecurityContext ์‚ญ์ œ ํ•ธ๋“ค๋Ÿฌ
    • ์ฟ ํ‚ค ์ •๋ณด ์‚ญ์ œ ํ•ธ๋“ค๋Ÿฌ
  • ๊ธฐ๋ณธ ๋กœ๊ทธ์•„์›ƒ ํ•ธ๋“ค๋Ÿฌ ์™ธ์—๋„ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด addLogoutHandler๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์ฐธ๊ณ ๋กœ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์˜ ๊ธฐ๋ณธ์ ์ธ ๋กœ๊ทธ์•„์›ƒ ์ฒ˜๋ฆฌ๋Š” post ๋ฐฉ์‹์ด๋‹ค.

 

 


 

๐Ÿ”น LogoutFilter

๋กœ๊ทธ์•„์›ƒ์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Logout Request๋ฅผ ๋ฐ›์•˜์„ ๋•Œ, Server์˜ ์„ธ์…˜์„ ๋ฌดํšจํ™”ํ•˜๊ณ , ์ฟ ํ‚ค ์ •๋ณด, ์ธ์ฆ ํ† ํฐ๊ณผ ์ธ์ฆ ํ† ํฐ์ด ์ €์žฅ๋œ Security Context์˜ ๊ฐ์ฒด๋ฅผ ์‚ญ์ œํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

๐Ÿ”น LogoutFilter ๋™์ž‘ ๋ฐฉ์‹

  • logoutUrl ๋ฉ”์„œ๋“œ๋กœ ์ง€์ •ํ–ˆ๋˜ Url๋กœ ์˜จ ์˜ฌ๋ฐ”๋ฅธ ์š”์ฒญ์ธ์ง€ ํ™•์ธํ•œ๋‹ค.
  • ์ง€์ •ํ–ˆ๋˜ Url๋กœ ๋“ค์–ด์˜จ ์š”์ฒญ์ด ๋งž๋‹ค๋ฉด, SecurityContext์—์„œ ์ธ์ฆ ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ธ๋‹ค.
  • ๊บผ๋‚ธ ์ธ์ฆ ๊ฐ์ฒด๋ฅผ SecurityContextLogoutHandler๋กœ ์ „๋‹ฌํ•œ๋‹ค.
    • ์ดํ›„, ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์„ธ์…˜ ๋ฌดํšจํ™”, ์ฟ ํ‚ค ์‚ญ์ œ, SecurityContext ์‚ญ์ œ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • ๋กœ๊ทธ์•„์›ƒ์ด ๋๋‚˜๋ฉด SimpleUrlLogoutSuccessHandler ํ˜ธ์ถœํ•˜์—ฌ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•œ๋‹ค.

 

 

 

 

 

๐Ÿ“ƒ reference