Spring Security는 기본적으로 세션 기반 인증을 사용한다. 하지만, JWT나 다른 인증 방식을 사용하도록 쉽게 확장할 수 있다.
1. 기본적으로 세션 기반 인증 : Spring Security는 기본적으로 세션 관리와 함께 동작한다. 인증에 성공하면 HttpSession에 사용자 정보를 저장하여 인증 상태를 유지한다. 이 방식은 다음과 같은 특징이 있다:
- 서버에서 세션을 관리하며, 세션 ID를 클라이언트에 쿠키로 전달한다.
- 서버 메모리에 세션 데이터를 저장하기 때문에 확장성 문제가 있을 수 있다.
- 상태를 서버에서 유지하기 때문에 상태 저장 방식(stateful)이다.
2. JWT 기반 인증 (Stateless 방식) : JWT(Json Web Token)는 Spring Security의 기본 설정이 아니지만, 이를 지원하도록 설정할 수 있다. JWT는 상태를 서버가 아닌 클라이언트에 유지하며, 다음과 같은 특징이 있다:
- 서버에서 세션을 유지하지 않음(무상태, stateless).
- JWT 토큰은 클라이언트가 요청 시마다 헤더(보통 Authorization 헤더)에 포함하여 서버에 전달한다.
- 서버는 토큰을 검증하여 사용자 정보를 확인합니다.
- 확장성이 뛰어나며, 분산 시스템에서 적합합니다.
3. Spring Security와 JWT 통합 : Spring Security에서 JWT를 사용하는 경우 다음과 같은 작업이 필요하다:
1) JWT 생성 및 검증 로직 구현: 인증 성공 시 JWT를 생성해 클라이언트에 반환한다. 요청 시 전달된 JWT를 검증하고 사용자 정보를 추출한다.
2) Stateless 모드 설정: http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
3) Custom Filter 추가: JWT 검증을 위한 필터를 Spring Security 필터 체인에 추가한다.
4) UserDetailsService 구현: 토큰에서 추출된 사용자 정보를 기반으로 UserDetails 객체를 생성한다.
어떤 방식을 사용할지는 목적에 따라 달라진다.
첫째, 세션 기반 인증: 서버에서 상태를 유지하고 관리해야 하는 애플리케이션에 적합하다. (예: 전통적인 웹 애플리케이션)
둘째, JWT 기반 인증: 마이크로서비스 아키텍처, 모바일 애플리케이션, SPA(Single Page Application)와 같은 무상태 애플리케이션에 적합하다.
---------------------------------- --------------------------------- -------------------------------- --------------------------------
Spring Security에서 JWT와 세션은 함께 사용할 수 있다. 두 가지를 병행하거나 선택적으로 사용할 수 있지만, 일반적으로 다음과 같은 방식으로 접근한다.
1. JWT와 세션을 함께 사용하는 경우 : JWT와 세션을 동시에 사용할 수 있지만, 이 방식은 특수한 요구 사항이 있을 때만 적합하다.
예를 들어
가) JWT를 인증 및 권한 관리를 위해 사용: 클라이언트는 JWT를 서버로 전송해 인증 및 권한 확인에 사용.
나) 세션을 특정 상태 저장에 사용: 예를 들어, 서버 측에서 사용자별 임시 데이터를 관리하는 용도로 세션 사용.
하지만 이러한 방식은 서버가 세션을 관리해야 하므로 Stateless의 장점이 약화될 수 있다.
설정 예: 세션을 유지하면서도 JWT를 활용하려면 SessionCreationPolicy를 ALWAYS 또는 IF_REQUIRED로 설정한다.
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 세션 활성화
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager())) // JWT 필터 추가
.authorizeRequests()
.anyRequest().authenticated();
2. JWT만 사용하는 경우 (Stateless) : JWT만 사용하는 방식은 서버가 사용자 상태를 저장하지 않으므로 완전히 Stateless하게 동작한다. 이는 다음과 같은 장점을 제공한다.
- 확장성: 서버 간 세션 공유 문제를 해결.
- 무상태 설계: 분산 시스템에서 적합.
JWT만 사용하는 경우에는 SessionCreationPolicy.STATELESS로 설정하여 세션을 비활성화한다.
설정 예:
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 세션 비활성화
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager())) // JWT 필터 추가
.authorizeRequests()
.anyRequest().authenticated();
3. JWT와 세션 중 하나만 사용하도록 분리 : 특정 API에서만 JWT를 사용하고, 다른 API에서는 세션을 사용하도록 구분할 수도 있다.
예를 들어
가) API 엔드포인트는 JWT로 인증.
나) 웹 애플리케이션은 세션으로 인증.
설정 예:
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 세션 활성화
.and()
.antMatcher("/api/**").sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // API는 Stateless
.authorizeRequests()
.anyRequest().authenticated();
그렇다면 어떤 방식을 선택할까?
- JWT만 사용: 클라이언트가 상태를 관리할 수 있고, 확장성이 중요한 경우.
- 세션만 사용: 서버에서 상태를 관리하며, 전통적인 애플리케이션에서 사용하는 경우.
- 두 가지를 병행: 특정한 비즈니스 요구 사항이 있을 때.
대부분의 경우 JWT와 세션을 동시에 사용하는 것은 불필요한 복잡성을 초래할 수 있으므로, 명확한 요구 사항이 없다면 하나를 선택하는 것이 바람직하다.