ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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편: 이메일 인증 및 비밀번호 재설정 – 보안성을 높이는 사용자 인증 흐름 구현

Designed by Tistory.