Spring-Security

동시 세션 제어

neal89 2025. 5. 29. 11:54

동시 세션 제어는 하나의 계정으로 동시에 로그인할 수 있는 세션 수를 제한하는 기능입니다.
예를 들어, 한 계정이 이미 로그인한 상태에서 다른 곳에서 또 로그인하면:

  • 기존 세션을 만료시킬 수도 있고,
  • 새 로그인 시도를 막을 수도 있습니다.

✅ 기본 설정 방식

Spring Security는 SessionManagementConfigurer를 통해 이 기능을 제공합니다.


✅ 예제 코드: 최대 1개의 세션만 허용

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .formLogin(withDefaults())
            .sessionManagement(session -> session
                .maximumSessions(1)                       // 최대 1개의 세션만 허용
                .maxSessionsPreventsLogin(false)         // true이면 새 로그인 거부, false이면 기존 세션 만료
                .expiredSessionStrategy(event -> {
                    System.out.println("세션이 만료되었습니다: " + event.getSessionInformation().getSessionId());
                })
            );
        return http.build();
    }
}

✅ 설정 설명

maximumSessions(1) 최대 허용 세션 수 (예: 1)
maxSessionsPreventsLogin(true) 새 로그인 거부 (true), 기존 세션 만료 (false)
expiredSessionStrategy(...) 기존 세션이 만료될 때의 커스텀 동작

✅ 동작 방식 요약

  1. 사용자가 로그인하면 세션이 생성되고 저장됨.
  2. 두 번째 로그인 시:
    • maxSessionsPreventsLogin(true) → 새 로그인 거부됨.
    • maxSessionsPreventsLogin(false) → 이전 세션이 강제 만료됨.
  3. 만료된 세션에서는 다시 요청 시 인증 예외가 발생함.

좋은 질문입니다!
expiredUrl("/expired")과 expiredSessionStrategy(...)는 동일한 상황(즉, 세션 만료)에서 서로 다른 방식으로 동작하기 때문에 같이 쓸 수는 있지만, 동시에 둘 다 적용되지는 않습니다.

 

 

**추가

expiredUrl vs expiredSessionStrategy

✅ 요약

설정 설명 우선순위

expiredUrl("/expired") 세션이 만료되면 지정된 URL로 리다이렉트 기본 방식
expiredSessionStrategy(...) 세션 만료 시 직접 로직을 실행 (예: JSON 응답, 로그 작성 등) 이 설정이 있으면 expiredUrl은 무시

즉, 둘 다 설정하면 expiredSessionStrategy가 우선이고, expiredUrl은 무시됩니다.


✅ 함께 작성한 예제 코드

http
  .sessionManagement(session -> session
    .maximumSessions(1)
    .expiredUrl("/expired") // 이건 무시됨
    .expiredSessionStrategy(event -> {
        // 직접 처리
        HttpServletResponse response = event.getResponse();
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getWriter().write("{\"message\": \"세션이 만료되었습니다.\"}");
    })
  );

✅ 언제 뭘 써야 할까?

단순히 세션 만료 시 페이지로 보내고 싶을 때 expiredUrl("/expired")
REST API 또는 사용자 정의 응답 처리 필요할 때 expiredSessionStrategy(...)