-
Spring Boot 시리즈 9편 – 로그인 및 인증 처리 전략: JWT 기반 인증 흐름과 보안 설계개발/Spring Boot 2025. 4. 24. 14:00
Spring Boot에서 JWT 기반 인증을 구현하는 방법을 설명합니다. 토큰 발급, 검증, Spring Security 연동, 보안 설계 전략까지 포함된 실전 인증 처리 가이드입니다.
Spring Boot 시리즈 9편 – 로그인 및 인증 처리 전략: JWT 기반 인증 흐름과 보안 설계
웹 애플리케이션이 성장하면서 로그인 처리 또한 단순 세션 기반에서 **토큰 기반 인증(JWT)**으로 빠르게 전환되고 있습니다.
이번 글에서는 Spring Boot 환경에서 JWT를 이용한 인증 흐름을 어떻게 설계하고 구현할 수 있는지,
그리고 Spring Security와 어떻게 통합하며 보안적으로 주의해야 할 점은 무엇인지 실무 중심으로 정리해보겠습니다.
📌 1. 왜 JWT인가?
✅ JWT(Json Web Token)의 특징
- 서버 상태를 저장하지 않는 Stateless 인증 구조
- 클라이언트가 토큰만 있으면 어디서나 인증 가능
- 로그인 이후 API 호출마다 Authorization 헤더만으로 인증 수행
✅ 전통적인 세션 방식과 비교
항목 세션 기반 JWT 기반
상태 저장 서버에 세션 저장 상태 없음 (Stateless) 확장성 서버 수 늘릴수록 복잡 확장 용이 (Load Balancer 친화적) 토큰 보관 위치 서버 클라이언트 (보통 LocalStorage or HttpOnly Cookie)
🛠️ 2. JWT 인증 흐름 설계
[1] 로그인 요청 (ID/PW) ↓ [2] 인증 성공 → JWT 발급 ↓ [3] 클라이언트가 토큰 저장 ↓ [4] API 요청 시 Authorization: Bearer {토큰} ↓ [5] JWT 유효성 검사 → 인증된 사용자로 요청 처리
✅ 3. JWT 발급 및 검증 구현
1️⃣ JWT Utility 클래스
@Component public class JwtTokenProvider { private final String secretKey = "my-secret-key"; // 환경 변수로 분리 권장 private final long validityInMs = 3600000; // 1시간 public String createToken(String userId, String role) { Claims claims = Jwts.claims().setSubject(userId); claims.put("role", role); Date now = new Date(); Date expiry = new Date(now.getTime() + validityInMs); return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(expiry) .signWith(SignatureAlgorithm.HS256, secretKey.getBytes()) .compact(); } public boolean validateToken(String token) { try { Jws<Claims> claims = Jwts.parser() .setSigningKey(secretKey.getBytes()) .parseClaimsJws(token); return !claims.getBody().getExpiration().before(new Date()); } catch (Exception e) { return false; } } public String getUserId(String token) { return Jwts.parser() .setSigningKey(secretKey.getBytes()) .parseClaimsJws(token) .getBody() .getSubject(); } }
🔐 4. Spring Security와 통합 – 필터 구성
1️⃣ SecurityConfig 설정
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JwtTokenProvider jwtTokenProvider; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .httpBasic().disable() .authorizeHttpRequests() .requestMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() .and() .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class); return http.build(); } }
2️⃣ JwtAuthenticationFilter
public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenProvider tokenProvider; public JwtAuthenticationFilter(JwtTokenProvider provider) { this.tokenProvider = provider; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String token = resolveToken(request); if (token != null && tokenProvider.validateToken(token)) { String userId = tokenProvider.getUserId(token); UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userId, "", List.of()); SecurityContextHolder.getContext().setAuthentication(auth); } chain.doFilter(request, response); } private String resolveToken(HttpServletRequest request) { String bearer = request.getHeader("Authorization"); return (bearer != null && bearer.startsWith("Bearer ")) ? bearer.substring(7) : null; } }
🧠 실무 적용 시 고려 사항
항목 전략
비밀키 관리 application.yml + 환경변수로 분리 토큰 만료 시간 액세스 토큰 15~60분, 리프레시 토큰은 7일 이상 사용자 권한 정보 role/permission claim으로 포함 가능 리프레시 토큰 별도 DB에 저장, Access 토큰 갱신용으로 사용 토큰 폐기 처리 블랙리스트 저장소(Redis 등) 사용
📦 로그인 요청/응답 구조 예시
🔹 로그인 요청
{ "email": "user@example.com", "password": "1234" }
🔹 로그인 성공 응답
{ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...", "expiresIn": 3600 }
이후 API 호출 시 Authorization: Bearer {accessToken} 헤더를 사용
✅ 마무리 요약
항목 핵심 요약
인증 방식 Stateless 구조의 JWT 기반 인증 핵심 구성 JwtTokenProvider, JwtAuthenticationFilter, Spring Security 토큰 구조 Subject(사용자 ID), Role, Expiration 포함 보안 전략 토큰 유효성 검사, 리프레시 토큰 분리, 예외 처리 통일 테스트 로그인 → 토큰 발급 → 인증이 필요한 API 호출로 흐름 검증
📌 다음 편 예고
Spring Boot 시리즈 10편: Spring Security로 인가 처리 확장 – 권한 기반 API 보호 전략
'개발 > Spring Boot' 카테고리의 다른 글
Spring Boot 시리즈 12편 – 파일 업로드 처리 전략: 이미지, 문서 업로드부터 S3 연동까지 (0) 2025.04.26 Spring Boot 시리즈 10편 – Spring Security로 인가 처리 확장: 권한 기반 API 보호 전략 (0) 2025.04.25 Spring Boot 시리즈 8편 – 입력값 검증 전략: @Valid부터 도메인 중심 유효성 설계까지 (0) 2025.04.24 Spring Boot 시리즈 7편 – API 응답 구조 표준화 전략: 성공과 실패를 구분하는 통일 설계 (0) 2025.04.23 Spring Boot 시리즈 6편 – Swagger를 활용한 API 문서 자동화 전략 (0) 2025.04.23