1. 강의 목표
- Spring Security의 기본 개념 이해
- JWT(Json Web Token)의 개념과 필요성 이해
- JWT를 활용한 인증 및 인가 구현
- 실전 예제를 통해 JWT 기반 인증 시스템 구축
2. Spring Security
1) 인증(Authentication) vs 인가(Authorization)
- Authentication(인증): 사용자의 신원을 확인하는 과정 (예: 로그인)
- Authorization(인가): 인증된 사용자가 특정 리소스에 접근할 수 있는 권한이 있는지 확인하는 과정
2) Spring Security의 구조
- Security Filter Chain: 요청이 들어오면 여러 개의 필터를 거쳐 보안 검사를 수행함
- UserDetailsService: 사용자 정보를 로드하는 인터페이스
- AuthenticationManager: 인증을 처리하는 핵심 컴포넌트
- PasswordEncoder: 비밀번호를 암호화 및 비교하는 기능 제공
3) 기본적인 Security 설정
ex) 버전 마다 다름
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public").permitAll()
.requestMatchers("/api/private").authenticated()
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
return http.build();
}
4) Spring Security 특징
- 서블릿 API 통합
- Spring Web MVC와의 선택적 통합
- 인증과 권한 부여를 확장 가능하게 지원
- 세션 고정, CSRF(사이트 간 요청 위조) , ClickJacking 등을 보호
5) Servlet Filter Chain

-
서블릿 필터 체인(Servlet Filter Chain) 흐름
→Spring Security의 필터 체인(Filter Chain) 동작 방식
- 사용자의 Request(요청)이 들어오면 여러 개의 Servlet Filter를 거침
- 각 필터는 doFilter() 메서드를 호출하며 체인을 따라 다음 필터로 요청을 전달
- 마지막으로 Servlet이 요청을 처리한 후, 다시 반대 방향으로 Response(응답)을 반환
- Spring Security에서는 이러한 필터 체인을 활용하여 JWT 검증, 인증(Authentication), 권한 확인(Authorization) 등의 작업을 수행
6) Spring Security 필터 흐름도

2. Spring Security 필터 흐름 및 구성 요소
-> Spring Security의 필터 및 보안 처리 흐름
- DelegatingFilterProxy
- Spring Security의 핵심 필터인 FilterChainProxy를 위임하는 역할
- 실제 필터 체인의 시작점이며, Spring Security의 여러 보안 필터를 실행
- FilterChainProxy
- 여러 개의 보안 필터(Security Filters)를 관리하는 Spring Security의 중심 필터 체인
- 사용자의 요청이 들어오면, 설정된 WebSecurity 설정을 기반으로 필터 체인을 구성하여 실행
- 인증(Authentication) 관련 필터
- UsernamePasswordAuthenticationFilter: 사용자의 아이디와 비밀번호를 검증하는 필터 (기본 로그인 처리)
- JwtAuthenticationFilter (추가 필요): JWT 기반 인증을 처리하는 커스텀 필터
- SecurityContextPersistenceFilter: 보안 컨텍스트(SecurityContext)를 유지하는 역할
- 인가(Authorization) 및 기타 보안 처리
- SessionManagementFilter: 세션을 관리하며, JWT를 사용하는 경우 STATELESS로 설정
- FilterSecurityInterceptor: 최종적으로 접근 권한을 체크하고 요청을 허용할지 결정하는 필터
- Spring Security 필터 체인의 핵심 개념
- 요청이 들어오면 DelegatingFilterProxy → FilterChainProxy가 이를 관리
- 각 필터를 순차적으로 실행하며 인증(Authentication)과 인가(Authorization) 수행
- 최종적으로 요청이 허용되면 Servlet에서 처리 후 응답을 반환
- JWT 기반 인증을 적용할 경우, JwtAuthenticationFilter를 추가하여 Access Token 검증
7) Spring Security 인증 과정 흐름도

1. 사용자의 HTTP 요청 (Http Request)
- 사용자가 로그인 요청을 보내거나 보호된 리소스에 접근하려 할 때 Spring Security의 Security Filter Chain이 이를 가로챔
2. AuthenticationFilter (인증 필터)
- Spring Security의 첫 번째 방어선으로, 들어오는 요청에서 인증 정보를 확인하는 역할
- JWT 기반 인증을 사용할 경우, JwtAuthenticationFilter를 여기에서 실행하여 토큰을 검증
- 인증 정보가 있다면 AuthenticationManager로 넘김
3. AuthenticationManager (인증 관리자)
- 실제 인증을 처리하는 역할을 담당
- 여러 개의 AuthenticationProvider 중 적절한 것을 찾아서 인증을 위임
4. AuthenticationProvider (인증 제공자)
- UserDetailsService를 사용하여 데이터베이스에서 사용자 정보를 가져오고, 비밀번호를 검증
- 여기에 PasswordEncoder 위치
- 인증이 성공하면, 인증된 사용자 정보를 반환
5. UserDetailsService (사용자 정보 로드)
- 데이터베이스에서 사용자 정보를 조회하고, UserDetails 객체로 반환
- 일반적으로 loadUserByUsername(String username) 메서드를 통해 사용자 정보를 가져옴
6. SecurityContextHolder (보안 컨텍스트 저장)
- 인증이 성공하면, SecurityContextHolder에 인증 정보를 저장
- 이후 요청에서 인증이 필요할 때마다 여기에서 인증 정보를 가져옴
7. FilterChain을 거쳐 컨트롤러(Spring Controller)로 요청 전달
- 인증이 완료되면, 요청이 정상적으로 필터 체인을 통과하고 Spring Controller로 전달
- 컨트롤러에서는 @AuthenticationPrincipal 어노테이션을 사용하여 사용자 정보를 가져옴
중요!!
- Spring Security는 AuthenticationFilter → AuthenticationManager → AuthenticationProvider → UserDetailsService 순서로 요청을 처리함.
- 사용자가 인증되면
SecurityContextHolder에 저장하여 이후 요청에서 재사용 가능.
- JWT 기반 인증을 사용할 경우, AuthenticationFilter에서 JWT 검증을 수행하고, 인증이 완료되면 SecurityContext에 저장하여 이후 인증 요청 시 활용.
3. JWT + Spring Security
1) JWT란?
- Json Web Token의 약자로, 인증 및 정보 교환을 위한 토큰 기반 인증 방식
- 세션 기반 인증과 다르게 서버가 상태를 유지할 필요 없음 (Stateless)
- HTTP 헤더에 포함되어 요청 시 전달됨
2) Access Token vs. Refresh Token
- Access Token: 사용자가 인증된 상태임을 나타내는 짧은 수명의 토큰
- 사용자가 인증된 상태임을 나타내는 토큰으로, 주로 짧은 만료 시간을 가짐 (예: 15~30분)
- 클라이언트가 요청을 보낼 때
Authorization: Bearer <Access Token> 헤더에 포함하여 서버로 전송함
- 서버는 토큰을 검증하여 사용자의 인증 정보를 확인함
- 만료되면 더 이상 사용할 수 없음 (재발급 필요)
- Refresh Token: Access Token이 만료되었을 때 새로운 Access Token을 발급하기 위한 토큰
- Access Token이 만료되었을 때 새로운 Access Token을 발급받기 위한 토큰
- 일반적으로 Access Token보다 긴 유효기간을 가짐 (예: 7일~30일)
- 보안상 중요하므로 서버(DB)에서 관리하는 경우가 많음
- Refresh Token을 사용해 새로운 Access Token을 요청하는 API (
/refresh)를 따로 구현해야 함
- JWT는 Stateless인데 왜 Refresh Token을 DB에서 관리할까?
- Access Token은 서버에서 상태를 저장하지 않아도 클라이언트에서 보관하고 전송할 수 있기 때문에 JWT의 장점(Stateless)을 활용할 수 있음.
- 하지만 Refresh Token은 보안성 문제로 인해 DB에 저장하는 것이 일반적
- Refresh Token이 탈취되었을 경우: 공격자가 무한히 Access Token을 발급할 수 있음
- 사용자가 로그아웃했을 경우: Refresh Token을 삭제하여 더 이상 Access Token을 갱신할 수 없도록 해야 함
- 다중 기기 지원: 각 기기별 Refresh Token을 관리하여 특정 기기에서만 로그아웃이 가능하도록 할 수 있음
4. Spring Security와 JWT의 연관성 및 인증/인가 과정
1) Spring Security와 JWT 연관성
- Spring Security는 기본적으로 세션 기반 인증을 사용하지만, JWT를 활용하면 세션 없이도 Stateless 인증이 가능
- JWT를 활용하면 Security Filter Chain에서 인증 필터를 추가하여 요청마다 토큰을 검증하고, SecurityContextHolder에 인증 정보를 저장
2) JWT 인증 및 인가 과정
- 사용자가 로그인 요청 (
/api/auth/login)
- 사용자가 아이디와 비밀번호를 입력하여 로그인 요청을 보냄
- AuthenticationManager가 UserDetailsService를 통해 사용자 정보를 조회하고 인증 수행
- 인증이 성공하면 JWT Access Token과 Refresh Token을 생성하여 반환
- 클라이언트가 Access Token을 포함하여 API 요청
- 클라이언트는 Authorization: Bearer 헤더를 포함하여 요청을 보냄
- 요청이 Security Filter Chain을 거치면서 JwtAuthenticationFilter에서 JWT 검증 수행
- JWT 검증 및 SecurityContextHolder에 저장
- JwtAuthenticationFilter에서 JWT의 서명을 검증하고, 토큰이 유효하면 SecurityContextHolder에 사용자 인증 정보 저장
- 이후의 모든 요청은 SecurityContext에서 인증 정보를 가져와 처리됨
- 인가(Authorization) 처리
- @PreAuthorize, @Secured, @RolesAllowed 등의 어노테이션을 활용하여 사용자의 권한을 확인하고 접근 제어 수행
- 예: @PreAuthorize("hasRole('ADMIN')")
- Access Token 만료 시 Refresh Token을 이용한 재발급
- 클라이언트가 Access Token이 만료되었을 경우, 저장된 Refresh Token을 이용하여 새로운 Access Token 요청 (/api/auth/refresh)
- 서버는 Refresh Token을 검증하고 새로운 Access Token을 생성하여 반환