Spring Security & JWT

gyeorrr·2025년 7월 14일

Spring

목록 보기
2/3

🔒 Spring Security & JWT A to Z: 설정부터 실제 구현까지

Spring Boot 환경에서 Security를 적용하고 JWT(JSON Web Token)를 이용한 인증/인가 시스템을 구축하는 전반적인 과정을 정리
초기 설정부터 주요 컴포넌트 구현, AOP와 예외 처리까지 실무적인 내용을 중심으로 다룰 것임


🚀 1. 프로젝트 초기 설정

가장 먼저 start.spring.io 또는 IDE를 통해 프로젝트를 생성하고, 필요한 의존성을 추가

Spring Initializr & Maven Dependencies

프로젝트에 필요한 핵심 라이브러리 목록

구분라이브러리 이름주요 용도
핵심Spring Web스프링 MVC, REST API 개발을 위한 필수 프레임워크
Spring Boot DevTools코드 변경 시 자동 재시작 등 개발 편의 기능
Lombok@Getter, @Builder 등 보일러플레이트 코드 자동 생성
보안Spring Security인증(Authentication)과 인가(Authorization) 처리
DBSpring Data JPA / MyBatis데이터베이스 연동 및 ORM / SQL Mapper
MySQL Driver / H2 Driver사용할 데이터베이스에 맞는 드라이버
JWTJava JWT (jjwt)JWT 생성 및 검증을 위한 라이브러리
기타Validation@Valid를 이용한 데이터 유효성 검사
Spring AOP관점 지향 프로그래밍, 공통 기능 모듈화
⚠️ Spring Boot 3.x / 2.7.x 버전 참고
최신 버전의 Spring Security에서는 WebSecurityConfigurerAdapter가 **Deprecated** 되었습니다. 이 글에서는 최신 트렌드에 맞는 컴포넌트 기반(SecurityFilterChain Bean 등록) 방식을 기준으로 설명

application.yml 기본 설정

데이터베이스 연결 정보와 JWT Secret Key를 설정

spring:
  # --- 데이터베이스 연결 설정 ---
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://YOUR_DATABASE_ENDPOINT:3306/YOUR_DB
    username: YOUR_USERNAME
    password: YOUR_PASSWORD

  # --- MyBatis Mapper 위치 설정 ---
  mybatis:
    mapper-locations:
      - /mappers/*.xml

# --- JWT Secret Key 설정 (반드시 복잡하고 긴 문자열 사용) ---
jwt:
  secret: afcc85d110b13b17778ae91687bec4c479936475f18a5fa74dfd8b9058488eb32fdb0c972331e36e169b8a39e52db462c628bcb1b9cdeef80fbfbc7a25979155cb55eb7de35d226a5b78e5f59ffa6421204fd53fe67f62c9c73e58eaf6e1c63cac965c602ee59e6710185217b391e100091417bf122826182c5582f75f71fc2ebbc3695438250cd3223161333589c59fae85736afa6d83276eec071b1ef1490c97521d79417ea27944d021859465ccdcfb5b3248eb43a467e243109c7665deb55145269980fddc447b8d0c9ab4a2220da605ec7dbc932137f536fe0e7b7d2aabf64f2e418833c05ad18a1fb2c775f993e2069a9c216c2376790cef15621a5ace

⚙️ 2. 핵심 Security 설정 (Config)

서버가 실행될 때 IoC 컨테이너에 등록되어 동작하는 설정 클래스들

SecurityConfig: 보안 규칙 정의

`SecurityConfig`는 애플리케이션의 전반적인 보안 규칙을 정의하는 가장 중요한 설정 파일

  @Configuration: 해당 클래스가 설정 파일임을 명시.
@EnableWebSecurity: Spring Security 활성화.
핵심 설정 내용:
CSRF, Form/HttpBasic 로그인 비활성화: JWT 토큰 방식을 사용하므로 csrf().disable(), formLogin().disable(), httpBasic().disable() 설정.
세션 관리: 세션을 사용하지 않는 무상태(Stateless) 방식으로 설정 (sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)).
요청별 인가 규칙: authorizeRequests()를 통해 특정 URL 패턴별 접근 권한 설정.
.antMatchers("/auth/**").permitAll(): /auth/로 시작하는 경로는 인증 없이 허용.
.anyRequest().authenticated(): 그 외 모든 요청은 인증 필요.
* 필터 추가: JWT 인증을 위한 커스텀 필터(JwtFilter)를 특정 필터(UsernamePasswordAuthenticationFilter) 앞에 추가.

WebMvcConfig: CORS 설정

`WebMvcConfig`는 다른 도메인(e.g., React 앱)에서의 요청을 허용하기 위한 CORS(Cross-Origin Resource Sharing) 설정을 담당

  핵심 설정: addCorsMappings() 메소드를 오버라이드.
allowedOrigins("*"): 모든 출처에서의 요청 허용.
`allowedMethods(""): 모든 HTTP 메소드(GET, POST 등) 허용. * allowedHeaders("*")`: 모든 HTTP 헤더 허용.

BeanConfig: 순환 참조 방지

무한 루프(순환 참조) 위험이 있는 객체들(e.g., BCryptPasswordEncoder)은 별도의 @Configuration 파일에서 @Bean으로 등록하여 관리하는 것이 안전함


🔑 3. JWT 토큰 인증

Stateless 환경을 위해 세션 대신 JWT를 사용한 인증 방식을 구현

Session vs. Token 인증 방식

구분세션(Session) 기반 인증토큰(Token) 기반 인증 (JWT)
상태 저장서버에 사용자 상태 저장 (Stateful)서버에 상태 저장 안 함 (Stateless)
인증 정보서버의 세션 저장소클라이언트 측 (로컬 스토리지, 쿠키)
확장성수평적 확장이 상대적으로 어려움수평적 확장이 용이
보안세션 ID만 전송되어 상대적으로 안전토큰 자체에 정보 포함, 탈취 시 위험
주요 사용처전통적인 웹 애플리케이션REST API, 모바일, MSA 환경

JWT 처리 흐름

  1. 사용자 로그인: 사용자가 ID/PW로 로그인 요청.
  2. 토큰 발급: 서버는 사용자 인증 후, Payload에 사용자 정보(ID 등)를 담아 암호화된 Access Token을 생성하여 클라이언트에게 응답.
  3. 토큰 저장: 클라이언트(브라우저)는 받은 토큰을 로컬 스토리지나 쿠키에 저장.
  4. 인증 요청: 클라이언트는 API 요청 시마다 HTTP Header의 Authorization 필드에 토큰을 "Bearer " 접두사와 함께 실어 보냄.
  5. 토큰 검증: 서버의 JwtFilter는 요청을 받으면 헤더에서 토큰을 추출하여 유효성을 검증.
  6. 인가 처리: 토큰이 유효하면, Payload에서 사용자 정보를 꺼내 SecurityContext에 인증 정보를 등록. 이후 컨트롤러는 인증된 사용자로 간주하고 요청을 처리.

주요 구현 컴포넌트

  JwtProvider: secret 키를 이용해 토큰을 생성하고, 들어온 토큰의 유효성을 검증하고, 토큰에서 Payload를 추출하는 핵심 로직 담당.
JwtFilter: 모든 요청에 앞서 실행되는 필터. Authorization 헤더에서 Bearer 토큰을 추출하여 JwtProvider에게 검증을 위임하고, 검증 성공 시 SecurityContextHolder에 인증 정보를 등록하는 역할.
* PrincipalUser: Spring Security가 인증 과정에서 사용하는 사용자 정보 객체. UserDetails 인터페이스를 구현하며, 사용자의 ID, PW(사용 안 함), 권한(Role) 정보 등을 가짐.


✨ 4. 부가 기능: AOP & 유효성 검사

Valid: 데이터 유효성 검사

DTO(Data Transfer Object)에 @Pattern, @NotBlank 등 어노테이션을 붙여 데이터 형식을 강제하고, Controller 메소드에서 @ValidBindingResult를 함께 사용하여 유효성 검사 결과를 처리.

AOP (Aspect Oriented Programming)

AOP는 여러 비즈니스 로직에서 반복되는 공통 기능(e.g., 로그 기록, 실행 시간 측정)을 별도의 'Aspect'로 분리하여 코드의 재사용성을 높이는 기술입니다.

  @Aspect: AOP 클래스임을 명시.
@Pointcut: Aspect를 적용할 지점(메소드 등)을 표현식으로 정의.
* @Around: Pointcut으로 지정된 메소드의 실행 전과 후에 원하는 로직을 추가. ProceedingJoinPoint.proceed()를 기준으로 전/후 처리 로직을 작성.


🚨 5. 전역 예외 처리

`@RestControllerAdvice`를 사용하여 여러 컨트롤러에서 발생하는 예외를 한 곳에서 공통으로 처리하고, 일관된 형식의 에러 메시지를 클라이언트에 반환합니다.

  @ExceptionHandler(CustomException.class): 특정 예외가 발생했을 때 실행될 메소드를 지정.
이를 통해 서비스 로직에서는 throw new CustomException(...)으로 예외를 발생시키기만 하면, Advice 클래스가 이를 잡아 지정된 ResponseEntity를 반환.


💻 6. 클라이언트 연동 (React)

  토큰 저장: 로그인 성공 시 서버로부터 받은 JWT를 로컬 스토리지(Local Storage)에 저장.
인증 헤더 추가: axios와 같은 HTTP 클라이언트 라이브러리에서 인터셉터(Interceptor)를 사용하여, 모든 API 요청 헤더에 로컬 스토리지의 토큰을 Authorization: Bearer ${token} 형식으로 자동으로 추가.
* 상태 관리: React-QueryRedux 등을 사용하여 사용자 로그인 상태 및 정보를 관리.

0개의 댓글