본문 바로가기

Spring Boot/Security 쿠키,세션 기반 인증,인가

세션 관리 설정과 커스터마이징 : 세션 만료 후 처리 전략

 - 세션 만료 상황에서 발생할 수 있는 문제들

 - 세션 만료 후 접근 처리 전략

 - 세션 만료시 사용자 경험을 개선하기 위한 리다이렉션 방식

 - InvalidSessionStrategy 인터페이스의 역할과 구현 방법

 - 실무에서 자주 사용되는 세션 만료 처리 패턴


세션 만료 후 처리 전략에 대한 이해

1. 개념

  • 세션은 일정 시간동안 사용자가 활동하지 않거나, 명시적으로 로그아웃하면 만료된다
  • 만료된 세션에 접근하면 사용자는 더이상 인증된 상태가 아니므로, 보안적인 조치가 필요하다
  • 잘못된 세션 접근시, 기본적으로 Spring Security 는 로그인 페이지로 리다이렉션 시킨다

세션 만료 후 처리 전략


만료된 세션 접근 처리

1. 기본 동작

Spring Security는 기본적으로 InvalidSessionStrategy 를 통해 만료된 세션 접근을 처리한다

아무 설정이 없다면, /login 페이지로 리다이렉션한다

 

 

2. 커스터마이징 필요성

단순히 로그인 페이지로 이동하는 것만으로는 부족할 수 있다

 - REST API의 경우 : JSON 응답으로 세션 만료를 알리는 것이 더 적절할 수 있다

 - 대규모 서비스의 경우 : 만료 원인을 명시적으로 보여주는 것이 필요하다


세션 만료시 리다이렉션 설정하기

1. 설정법

http.sessionManagement() 설정에서 invalidSessionUrl 또는 InvalidSessionStrategy 를 지정할 수 있다

    @Bean
    @Order(1)
    public SecurityFilterChain meFilterChain(HttpSecurity http) throws Exception {
        http
                .securityMatcher("/me/**")
                .csrf(csrf -> csrf.disable())
                .sessionManagement(session -> session
                        
                        // 사용할 수 없는 세션 사용시 이동할 URL, 단순 URL 지정
                        .invalidSessionUrl("/session-expired")
                        
                        .maximumSessions(1) // 최대 1개의 세션만 허용하기
                        .expiredUrl("/auths/login-form") // 세션 만료시 이동할 URL, 로그인 다시 하세요
                )
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/me/**").authenticated()
                        .anyRequest().authenticated()
                )
                .httpBasic(Customizer.withDefaults());
        return http.build();
    }

 

.invalidSessionUrl("/session-expired") 설정은 세션이 만료되면 /session-expired 경로로 리다이렉션 시켜준다

 

 

2. 리다이렉션 페이지 예

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class SessionController {
    @GetMapping("/session-expired")
    public String sessionExpired(Model model) {
        model.addAttribute("msg", "세션이 만료되었습니다. 다시 로그인해주세요");
        return "session-expired";
    }
}

 

<!-- templates/session-expired.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>세션 만료</title>
</head>
<body>
    <h2 th:text="${msg}"></h2>
    <a href = "/login">로그인 페이지로 이동</a>
</body>
</html>

InvalidSessionStrategy 구현하기

1. 인터페이스 개념

세션이 만료되었을 때 동작을 직접 정의할 수 있는 인터페이스임

다양한 시나리오(웹, API, SPA 등)에 맞게 커스터마이징 할 수 있음

메서드 설명
onInvalidSessionDetected(HttpServletRequest request,
    HttpServletResponse response)
세션 만료시 호출되는 콜백임

 

 

 

2. 커스텀 구현 예시

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class CustomInvalidSessionStrategy implements InvalidSessionStrategy {
    
    @Override
    public void onInvalidSessionDetected(HttpServletRequest request,
                                         HttpServletResponse response) throws IOException, ServletException {
        // REST API 응답 예
        response.setContentType("application/json; charset=UTF-8"); // 응답 타입 정해주기
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401
        response.getWriter().write("{\"error\": \"세션이 만료되었습니다. 다시 로그인해주세요.\"}");
        response.getWriter().flush(); // flush로 한번에 보내기
    }
}

 

위에서 세션이 만료되면 JSON 응답을 반환하도록 처리함

 

 

 

3. SecurityConfig 에 적용하기

@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    private final CustomInvalidSessionStrategy invalidSessionStrategy; // 1. 필드 선언

    public SecurityConfig(CustomInvalidSessionStrategy invalidSessionStrategy) { // 2. 생성자에 주입
        this.invalidSessionStrategy = invalidSessionStrategy;
    }

    @Bean
    @Order(1)
    public SecurityFilterChain meFilterChain(HttpSecurity http) throws Exception {
        http
                .securityMatcher("/me/**")
                .csrf(csrf -> csrf.disable())
                .sessionManagement(session -> session
                        // 사용할 수 없는 세션 사용시 이동할 URL, 단순 URL 지정
                        .invalidSessionUrl("/session-expired")
                        
                        // 여기 invalidSessionStrategy를 메서드를 통해 주입
                        .invalidSessionStrategy(invalidSessionStrategy)
                )
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/me/**").authenticated()
                        .anyRequest().authenticated()
                )
                .httpBasic(Customizer.withDefaults());
        return http.build();
    }
    
 }

 


  • REST API 에서는 InvalidSessionStrategy 를 활용해서 JSON 응답을 제공하는게 적절하다
  • 웹 애플리케이션에서는 사용자 친화적인 만료 안내 페이지를 제공하는게 좋다
  • SPA 환경에서는 만료시 API 응답을 프론트엔드에서 감지하여 로그인 화면으로 리다이렉션한다
  • 보안상 만료 메시지에는 민감한 정보(세션 ID 등)를 절대 포함하지 않아야 한다

정리

주제 핵심 포인트
세션 만료 접근 처리 기본적으로 로그인 페이지(/login)로 리다이렉션
리다이렉션 설정 invalidSessionUrl 사용 가능
InvalidSessionStrategy 세션 만료시 동작을 직접 정의 가능
실무 활용 웹은 안내 페이지, API는 JSON 응답을 해줌