개발/Spring Boot
Spring Boot 시리즈 23편 – 인증과 권한 전략 아키텍처: OAuth2, JWT, Role 기반 접근 제어까지
B컷개발자
2025. 5. 2. 09:43
Spring Boot에서 OAuth2, JWT 기반 인증 및 권한 관리를 안전하게 구현하는 전략을 소개합니다. 실무 중심의 Role 기반 접근 제어 설계와 구현 사례 포함.
Spring Boot 시리즈 23편 – 인증과 권한 전략 아키텍처: OAuth2, JWT, Role 기반 접근 제어까지
서비스가 성장하면 단순한 로그인 처리만으로는 부족합니다.
외부 연동(OAuth), 모바일/웹 통합 인증, 사용자 권한별 기능 제한 등
강력하면서도 유연한 인증·권한 아키텍처가 필요해집니다.
이번 글에서는 Spring Boot 기반으로
- OAuth2 로그인
- JWT 토큰 인증
- Role/Permission 기반 인가 처리
전반을 실전 아키텍처 수준으로 정리합니다.
📌 1. 인증 vs 권한 – 구분부터 명확히
개념 설명
인증(Authentication) | "누구인지" 확인 – 로그인, 토큰 |
권한(Authorization) | "무엇을 할 수 있는지" 확인 – 역할, 권한 |
✅ 2. 인증 흐름 설계 – OAuth2 + JWT 구조
[1] 사용자가 Google 등으로 로그인 요청
↓
[2] OAuth2 서버로 인증 요청 → 성공
↓
[3] 우리 서버에서 JWT 토큰 발급 (Access + Refresh)
↓
[4] 클라이언트는 AccessToken 포함하여 API 호출
↓
[5] 서버는 토큰 인증 후 사용자 정보 주입
- OAuth2는 사용자 인증 대행
- JWT는 우리 서비스의 인증 상태 유지
🛠️ 3. Spring Boot에서 OAuth2 로그인 설정
1️⃣ 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
2️⃣ application.yml 설정 (Google 예시)
spring:
security:
oauth2:
client:
registration:
google:
client-id: {클라이언트ID}
client-secret: {클라이언트비밀}
redirect-uri: "{baseUrl}/login/oauth2/code/google"
scope: profile, email
3️⃣ OAuth2 로그인 성공 시 JWT 발급 로직
@Service
public class OAuth2UserService extends DefaultOAuth2UserService {
@Override
public OAuth2User loadUser(OAuth2UserRequest request) {
OAuth2User oauth2User = super.loadUser(request);
String email = oauth2User.getAttribute("email");
// 사용자 정보 확인/저장
User user = userRepository.findOrCreate(email);
// JWT 토큰 생성 후 리다이렉트 or API 응답
String token = jwtProvider.createToken(user.getId(), user.getRole());
return new CustomOAuth2User(token, user);
}
}
🔐 4. JWT 인증 구조 구현
1️⃣ JwtProvider 클래스
public class JwtProvider {
private final String secret = "secret-key";
public String createToken(String userId, String role) {
return Jwts.builder()
.setSubject(userId)
.claim("role", role)
.setExpiration(new Date(System.currentTimeMillis() + 3600_000))
.signWith(SignatureAlgorithm.HS512, secret.getBytes())
.compact();
}
public boolean validate(String token) {
try {
Jwts.parser().setSigningKey(secret.getBytes()).parseClaimsJws(token);
return true;
} catch (JwtException e) {
return false;
}
}
public String getUserId(String token) {
return Jwts.parser()
.setSigningKey(secret.getBytes())
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
2️⃣ JWT 필터 구현
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtProvider jwtProvider;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
String token = extractToken(request);
if (token != null && jwtProvider.validate(token)) {
String userId = jwtProvider.getUserId(token);
Authentication auth = new UsernamePasswordAuthenticationToken(userId, null, List.of());
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
}
✅ 5. 권한 관리 – Role 기반 인가 처리
1️⃣ Security 설정
http
.authorizeHttpRequests()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
2️⃣ 메서드 수준 제어 (@PreAuthorize)
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// 관리자만 가능
}
- Spring Expression Language(SpEL)를 활용한 세밀한 제어 가능
🧠 실무 적용 전략 요약
항목 전략
인증 방식 | OAuth2 → JWT로 변환하여 자체 인증 토큰 유지 |
토큰 저장 | Access + Refresh Token 분리 관리 |
역할 설계 | USER, ADMIN 등 enum 기반 권한 체계 확립 |
보안 처리 | Token 만료 시간, 서명 검증, Redis 블랙리스트 가능 |
클라이언트 대응 | 로그인 성공 → JWT 저장 (쿠키 or LocalStorage) |
✅ 마무리 요약
항목 요약
인증 | OAuth2 기반 외부 로그인, JWT로 자체 인증 유지 |
인가 | Role/Permission 기반 API 보호 |
필터 구성 | JWT 필터를 Security 체인에 삽입 |
실무 포인트 | Refresh 토큰 재발급, 토큰 만료 관리, 권한 계층 분리 필요 |
확장 방향 | API Gateway 인증 연계, OpenID Connect 확장 |
📌 다음 편 예고
Spring Boot 시리즈 24편: Swagger와 SpringDoc을 활용한 API 문서 자동화 전략