1. 소개
Spring Security는 Spring 기반 애플리케이션을 보호하기 위한 표준입니다. 로그인 및 로그아웃을 포함하여 사용자 인증을 관리하는 여러 기능이 있습니다.
이 예제에서는 Spring Security를 사용한 수동 로그아웃 에 중점을 둘 것 입니다.
독자가 이미 표준 Spring Security 로그아웃 프로세스를 이해하고 있다고 가정합니다.
2. 기본 로그아웃
사용자가 로그아웃을 시도 하면 현재 세션 상태에 여러 가지 결과가 있습니다 . 다음 두 단계로 세션을 파괴해야 합니다.
- HTTP 세션 정보를 무효화합니다.
- 인증 정보가 포함되어 있으므로 SecurityContext 를 지 웁니다 .
이 두 가지 작업은 SecurityContextLogoutHandler에 의해 수행됩니다.
실제로 작동하는지 봅시다.
@Configuration
public class DefaultLogoutConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.logout(logout -> logout
.logoutUrl("/basic/basiclogout")
.addLogoutHandler(new SecurityContextLogoutHandler())
);
return http.build();
}
}
SecurityContextLogoutHandler 는 기본적으로 Spring Security에 의해 추가됩니다. 명확성을 위해 여기에 표시합니다.
3. 쿠키 삭제 로그아웃
종종 로그아웃 시 사용자 쿠키의 일부 또는 전체를 지워야 합니다.
이를 위해 모든 쿠키를 반복하고 로그아웃 시 만료되는 자체 LogoutHandler 를 만들 수 있습니다 .
@Configuration
public class AllCookieClearingLogoutConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.logout(logout -> logout
.logoutUrl("/cookies/cookielogout")
.addLogoutHandler((request, response, auth) -> {
for (Cookie cookie : request.getCookies()) {
String cookieName = cookie.getName();
Cookie cookieToDelete = new Cookie(cookieName, null);
cookieToDelete.setMaxAge(0);
response.addCookie(cookieToDelete);
}
})
);
return http.build();
}
}
실제로 Spring Security는 쿠키 제거를 위해 즉시 사용할 수 있는 로그아웃 핸들러인 CookieClearingLogoutHandler 를 제공합니다.
4. Clear-Site-Data 헤더 로그아웃
마찬가지로 특별한 HTTP 응답 헤더를 사용하여 동일한 결과를 얻을 수 있습니다. 이것이 Clear-Site-Data 헤더 가 작동하는 곳입니다.
기본적으로 Clear-Data-Site 헤더는 요청한 웹사이트와 관련된 검색 데이터(쿠키, 저장소, 캐시)를 지웁니다.
@Configuration
public class ClearSiteDataHeaderLogoutConfiguration {
private static final ClearSiteDataHeaderWriter.Directive[] SOURCE =
{CACHE, COOKIES, STORAGE, EXECUTION_CONTEXTS};
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.logout(logout -> logout
.logoutUrl("/csd/csdlogout")
.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(SOURCE)))
);
return http.build();
}
}
그러나 한 가지 유형의 스토리지만 지울 때 스토리지 정리로 인해 애플리케이션 상태가 손상될 수 있습니다. 따라서 Incomplete Clearing 으로 인해 요청이 안전한 경우에만 헤더가 적용됩니다.
5. 요청 시 로그아웃
마찬가지로 HttpServletRequest.logout() 메서드를 사용하여 사용자를 로그아웃할 수 있습니다.
먼저 요청에 대해 수동으로 logout() 을 호출하는 데 필요한 구성을 추가해 보겠습니다 .
@Configuration
public static class LogoutOnRequestConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.antMatcher("/request/**")
.authorizeRequests(authz -> authz.anyRequest()
.permitAll())
.logout(logout -> logout.logoutUrl("/request/logout")
.addLogoutHandler((request, response, auth) -> {
try {
request.logout();
} catch (ServletException e) {
logger.error(e.getMessage());
}
}));
return http.build();
}
}
마지막으로 모든 것이 예상대로 작동하는지 확인하는 테스트 케이스를 만들어 보겠습니다.
@Test
public void givenLoggedUserWhenUserLogoutOnRequestThenSessionCleared() throws Exception {
this.mockMvc.perform(post("/request/logout").secure(true)
.with(csrf()))
.andExpect(status().is3xxRedirection())
.andExpect(unauthenticated())
.andReturn();
}
6. 결론
요약하면, Spring Security에는 인증 시나리오를 처리하기 위한 많은 내장 기능이 있습니다. 프로그래밍 방식으로 이러한 기능을 사용하는 방법을 마스터하는 것은 항상 편리합니다.
항상 그렇듯이 이 예제의 코드는 GitHub에서 사용할 수 있습니다 .