-
Spring Boot 시리즈 10편 – Spring Security로 인가 처리 확장: 권한 기반 API 보호 전략개발/Spring Boot 2025. 4. 25. 20:00
Spring Boot에서 Spring Security를 활용한 인가(Authorization) 전략을 소개합니다. 역할 기반 접근 제어, @PreAuthorize, 관리자/사용자 분리 구조 등 실무 적용 중심으로 설명합니다.
Spring Boot 시리즈 10편 – Spring Security로 인가 처리 확장: 권한 기반 API 보호 전략
API 인증이 끝났다고 해서 모든 보안이 끝난 것은 아닙니다.
**인증(Authentication)**은 “누구냐”를 확인하는 것이고,
**인가(Authorization)**는 “무엇을 할 수 있느냐”를 통제하는 일입니다.이번 편에서는 JWT 기반 인증 후, **사용자 권한(Role)**을 기준으로
Spring Security를 통해 API 접근 권한을 어떻게 세밀하게 제어할 수 있는지 정리합니다.
📌 1. 인가(Authorization)의 중요성
✅ 인가가 필요한 상황 예시
- 일반 사용자는 자신의 글만 수정 가능해야 함
- 관리자는 모든 사용자 목록에 접근할 수 있어야 함
- 특정 API는 관리자(Admin)만 호출 가능해야 함
- 이벤트성 기능은 특정 기간에만 접근 가능해야 함
이러한 요구사항을 제대로 처리하지 않으면 권한 없는 사용자에게 민감한 데이터가 노출되는 보안 사고로 이어질 수 있습니다.
🧱 2. 사용자 권한(Role) 기반 구조 설계
1️⃣ JWT에 Role 포함하기
claims.put("role", "ROLE_USER"); // 또는 ROLE_ADMIN
- Role은 JWT claim에 함께 포함하여 클라이언트가 별도 호출 없이도 인증 및 권한 정보를 활용할 수 있도록 설계
2️⃣ JWT → Authentication 객체 변환
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userId, "", List.of(new SimpleGrantedAuthority("ROLE_USER"))); SecurityContextHolder.getContext().setAuthentication(auth);
- GrantedAuthority를 통해 Spring Security가 인가 판단을 수행할 수 있도록 구성
🔐 3. Security 설정에서 인가 정책 설정
1️⃣ WebSecurityConfigurer 또는 SecurityFilterChain에서 인가 설정
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeHttpRequests() .requestMatchers("/api/admin/**").hasRole("ADMIN") .requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN") .anyRequest().authenticated(); return http.build(); }
- hasRole()은 내부적으로 "ROLE_" prefix를 자동으로 붙임
(즉 hasRole("ADMIN") → "ROLE_ADMIN")
✅ 4. 메서드 레벨 보안 적용 (@PreAuthorize)
1️⃣ 메서드 기반 인가 활성화
@EnableMethodSecurity // Spring Security 6.x 이상 (기존: @EnableGlobalMethodSecurity) @Configuration public class MethodSecurityConfig { }
2️⃣ @PreAuthorize 적용 예시
@PreAuthorize("hasRole('ADMIN')") public void deleteUser(Long userId) { // 관리자만 삭제 가능 } @PreAuthorize("#userId == authentication.name") public UserDto getMyProfile(Long userId) { // 본인만 접근 가능 }
- authentication.name은 Authentication.getName()으로부터 사용자 ID를 가져옴
- SpEL(Spring Expression Language)을 통해 권한/조건을 유연하게 제어 가능
🔐 실무 예: 본인 소유 데이터만 수정 허용
@PreAuthorize("#request.userId == authentication.name") @PostMapping("/api/user/update") public ApiResponse<Void> updateUser(@RequestBody UpdateUserRequest request) { userService.update(request); return ApiResponse.success(); }
🛠️ 5. 실무 고려사항
항목 전략
ROLE 네이밍 "ROLE_USER", "ROLE_ADMIN" 일관된 규칙 사용 JWT 내 Claim 정합성 변조 방지를 위한 서명 검증 필수 사용자 ID 확인 토큰 내부 Subject or claim 활용 (getUserId) 예외 응답 처리 접근 거부 시 403 반환 + AccessDeniedHandler 커스터마이징 도메인 보호 정책 도메인 내부에서도 ID 비교 로직 이중 적용 권장
📦 예외 처리 확장 – 403 응답 제어
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.exceptionHandling() .accessDeniedHandler((request, response, accessDeniedException) -> { response.setStatus(HttpStatus.FORBIDDEN.value()); response.setContentType("application/json"); response.getWriter().write( new ObjectMapper().writeValueAsString( ApiResponse.fail("A403", "접근 권한이 없습니다.", null) ) ); }); return http.build(); }
- 클라이언트는 403 응답을 명확하게 파악하고 UX 처리를 할 수 있음
✅ 마무리 요약
항목 요약
인증 vs 인가 인증은 사용자 확인, 인가는 권한 확인 Role 기반 보호 API 경로별 or 메서드별로 hasRole, @PreAuthorize로 제어 JWT 내 권한 정보 role claim 활용 + GrantedAuthority 설정 세밀한 제어 SpEL을 활용한 사용자 ID 비교, 조건부 접근 제어 가능 실무 주의 사용자 ID 일치 확인은 Controller + Domain 양쪽에서 보완
📌 다음 편 예고
Spring Boot 시리즈 11편: 이메일 인증 및 비밀번호 재설정 – 보안성을 높이는 사용자 인증 흐름 구현
'개발 > Spring Boot' 카테고리의 다른 글
Spring Boot 시리즈 13편 – 스케줄러와 배치 처리 전략: Spring Task와 Quartz 실전 가이드 (0) 2025.04.26 Spring Boot 시리즈 12편 – 파일 업로드 처리 전략: 이미지, 문서 업로드부터 S3 연동까지 (0) 2025.04.26 Spring Boot 시리즈 9편 – 로그인 및 인증 처리 전략: JWT 기반 인증 흐름과 보안 설계 (0) 2025.04.24 Spring Boot 시리즈 8편 – 입력값 검증 전략: @Valid부터 도메인 중심 유효성 설계까지 (0) 2025.04.24 Spring Boot 시리즈 7편 – API 응답 구조 표준화 전략: 성공과 실패를 구분하는 통일 설계 (0) 2025.04.23