🔐 JWT, 🛡️ Spring Security & 🌐 OAuth2 정리
🧾 JWT (JSON WEB TOKEN)
💡 개념 요약
- 정의: JSON 형식의 데이터를 안전하게 사용하기 위한 토큰 기반 인증 방식
- 사용처: 웹/앱의 인증(Authentication) 및 권한 부여(Authorization)
- 장점:
| 번호 | 장점 | 설명 |
|---|
| 1️⃣ | HTTP 지원 | 헤더 정보에 토큰 정보를 담을 수 있음 |
| 2️⃣ | 보안 | 서명 알고리즘으로 위·변조 방지 |
| 3️⃣ | 무상태 | 서버 세션 불필요, 클라이언트가 상태 관리 |
🔍 구조
| 구성 요소 | 설명 |
|---|
| Header | 알고리즘 정보 및 JWT 타입 |
| Payload | 실제 데이터(Claim), 발급 시간 등 포함 |
| Signature | 비밀키로 서명된 인증 부분 |
형태: (header).(payload).(signature)
🔗 확장 기능
| 연동 대상 | 설명 |
|---|
| 🍪 쿠키 | JWT를 쿠키에 저장하여 클라이언트에서 관리 |
| 💾 Redis | 서로 다른 서버 간 토큰 공유 (분산 환경에서 활용) |
⚙️ 설치 (build.gradle)
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
🧰 사용법
1️⃣ 비밀키 생성
String secret = "32자리이상비밀키";
private final Key secretKey = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
2️⃣ 토큰 생성
String token = Jwts.builder()
.claim(key, value)
.setIssuedAt(현재시간)
.setExpiration(만료시간)
.signWith(비밀키, 알고리즘)
.compact();
3️⃣ 토큰 검증
Jwts.parser()
.setSigningKey(비밀키)
.build()
.parseClaimsJws(검증할토큰);
4️⃣ 토큰 값 추출
Claims claims = Jwts.parser()
.setSigningKey(비밀키)
.build()
.parseClaimsJws(추출할토큰)
.getBody();
🛡️ Spring Security
💬 개념 요약
- Spring 기반의 인증(Authentication) 과 인가(Authorization) 제공 라이브러리
- 대표 기능: 로그인, 소셜 로그인, 로그아웃, CSRF 공격 방지 등
⚙️ 설치 (build.gradle)
implementation 'org.springframework.boot:spring-boot-starter-security'
설치 시 기본 보안 필터 체인이 자동 적용됨 (로그인/권한 검증 등)
🧩 Security Custom 설정
| 단계 | 설정 항목 | 코드 예시 | 설명 |
|---|
| 1️⃣ | HTTP 요청 필터 | httpSecurity.authorizeHttpRequests(req -> req.requestMatchers("경로").hasRole("권한")); | 요청별 접근 권한 설정 |
| 2️⃣ | CSRF 요청 필터 | httpSecurity.csrf(csrf -> csrf.disable()); | CSRF 공격 방지 해제(개발단계 권장) |
| 3️⃣ | 세션 종료 설정 | sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); | 쿠키·JWT 기반 인증 시 필수 |
| 4️⃣ | JWT 필터 등록 | addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); | 커스텀 토큰 필터 등록 |
| 5️⃣ | 메서드 보안 어노테이션 | @PreAuthorize("hasRole('ROLE_ADMIN')") | Controller 메서드 단위 권한 지정 |
⚔️ Security 주요 옵션 비교
| 기능 | 코드 | 설명 |
|---|
| 권한 제한 | .hasRole("ADMIN") | 지정된 권한만 접근 허용 |
| 여러 권한 허용 | .hasAnyRole("USER", "ADMIN") | 여러 권한 모두 허용 |
| 전체 허용 | .permitAll() | 모든 사용자 접근 허용 |
| CSRF 제외 경로 지정 | .csrf(csrf -> csrf.ignoringRequestMatchers("/api/public/**")) | 특정 경로만 CSRF 예외 처리 |
🔐 쿠키 + 토큰 사용 시 주의점
| 설정 항목 | 코드 | 설명 |
|---|
| 세션 종료 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) | 세션 대신 JWT 사용 |
| 커스텀 필터 등록 | .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) | JWT 필터를 인증 필터 이전 실행 |
💡 JwtService를 시큐리티와 통합하려면 OncePerRequestFilter 상속 후 doFilterInternal() 오버라이딩
🌐 OAuth2
📦 설치 (build.gradle)
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
⚙️ 설정 예시 (OAuth2 Login Filter)
httpSecurity.oauth2Login(oauth -> oauth
.loginPage("/oauth2/authorization/google")
.successHandler(oauth2SuccessHandler)
);
🔧 로그인 성공 후 동작 (onAuthenticationSuccess 오버라이딩)
| 단계 | 설명 | 코드 예시 |
|---|
| 1️⃣ | 로그인 제공자 확인 | OAuth2AuthenticationToken oAuthToken = (OAuth2AuthenticationToken) authentication; |
| 2️⃣ | 사용자 정보 가져오기 | OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal(); |
| 3️⃣ | 내 서버와 통합 로그인 | JWT + 쿠키 or 세션 사용 |
| 4️⃣ | DB 통합 | 최초 로그인 시 DB 저장, 이후 로그인 시 기존 정보 사용 |