Spring

Spring AOP를 활용해서 권한 체크 하기

Griotold 2025. 3. 6. 18:33

 

1. 개요

 

Spring AOP(Aspect-Oriented Programming)를 활용하면,

권한 체크 로직을 모든 컨트롤러 메서드마다 반복해서 작성할 필요 없이

관점 지향 프로그래밍(Aspect-Oriented Programming) 방식으로 깔끔하게 분리할 수 있다.

Spring AOP를 이용하여 API 호출 시 특정 역할(Role)만 접근 가능하도록 제한하는 방법을 정리하겠다.

 

2. 구현

2 - 1. @RequireRole 어노테이션 생성

 

먼저, 권한 체크를 적용할 메서드에 사용할 커스텀 어노테이션을 생성한다.

package com.example.infra.aspect;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD) // 메서드에만 적용 가능
@Retention(RetentionPolicy.RUNTIME) // 런타임에도 유지됨
public @interface RequireRole {
    String[] value(); // 허용된 권한 리스트
}

 

이제 @RequireRole({"MASTER", "HUB"}) 와 같이 특정 역할을 가진 사용자만 접근할 수 있도록 설정할 수 있다.

 

2 - 2. AOP 클래스 구현

 

package com.example.infra.aspect;

import com.example.common.exception.ErrorCode;
import com.example.common.exception.CustomException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.List;

@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class RoleCheckAspect {

    private final HttpServletRequest request;

    @Before("@annotation(requireRole)")
    public void checkRole(RequireRole requireRole) {
        // 헤더에서 역할(Role) 정보 가져오기
        String role = request.getHeader("X-Role");
        if (role == null) {
            throw new CustomException(ErrorCode.MISSING_ROLE);
        }

        log.info("Checking role: {}", role);
        // 허용된 권한 체크
        List<String> allowedRoles = List.of(requireRole.value());
        if (!allowedRoles.contains(role)) {
            throw new CustomException(ErrorCode.FORBIDDEN_ACCESS);
        }
    }
}

 

 

✨ 주요 로직 설명

  1. HTTP 요청 헤더에서 X-Role 값을 가져온다.
  2. 헤더 값이 없으면 예외를 발생시킨다. (ErrorCode.MISSING_ROLE)
  3. 해당 역할이 어노테이션에 명시된 값과 일치하지 않으면 예외를 발생시킨다. (ErrorCode.FORBIDDEN_ACCESS)
  4. AOP를 적용하여 메서드 실행 전에 @RequireRole이 붙어 있는 경우 권한을 체크한다.

 

2 - 3. AOP 설정 활성화

 

Spring에서 AOP를 활성화하려면 @EnableAspectJAutoProxy를 설정해야 한다.

package com.example.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // CGLIB 기반 프록시 사용
public class AopConfig {
}

 

🔍 proxyTargetClass = true를 사용하는 이유

  • Spring AOP는 기본적으로 JDK 동적 프록시(인터페이스 기반)와 CGLIB 프록시(클래스 기반) 두 가지 방식이 있다.
  • proxyTargetClass = true를 설정하면 인터페이스가 없어도 프록시 적용 가능하며,
  • 클래스 기반(CGLIB) 프록시를 강제 사용합니다.
  • 인터페이스가 없는 클래스에도 AOP 적용이 필요할 때 유용합니다.

 

2 - 4. 컨트롤러에 적용

 

이제 실제 컨트롤러에서 @RequireRole을 활용하여 특정 API에 대해 권한 체크를 수행할 수 있다.

 

package com.example.controller;

import com.example.common.response.ApiResponse;
import com.example.dto.CompanyResponse;
import com.example.service.CompanyService;
import com.example.infra.aspect.RequireRole;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RequiredArgsConstructor
@RequestMapping("/api/companies")
@RestController
public class CompanyController {

    private final CompanyService companyService;

    /**
     * 업체 생성 (MASTER, ADMIN 역할만 가능)
     */
    @RequireRole({"MASTER", "HUB"})
    @PostMapping
    public ApiResponse<CompanyResponse> createCompany(
            @RequestHeader("X-User-Id") String userId,
            @RequestHeader("X-Role") String role) {
        log.info("User ID: {}, Role: {}", userId, role);
        CompanyResponse response = companyService.createCompany(userId);
        return ApiResponse.success(response);
    }
}

 

이제 @RequireRole({"MASTER", "HUB"})이 적용된 createCompany() 메서드는

MASTER 또는 HUB 역할을 가진 사용자만 호출할 수 있습니다.

 

3. 테스트 하기

3 - 1. MASTER, HUB 가 아닌 권한으로 createCompany를 호출 했을 때

 

3 - 2. MASTER 또는, HUB 권한으로 createCompany를 호출 했을 때

4. 정리

  • AOP를 사용하여 API의 권한 체크 로직을 깔끔하게 분리할 수 있었다.
  • 중복되는 코드 없이 어노테이션만으로 특정 API의 접근 권한을 쉽게 설정할 수 있다.
  • Spring AOP를 사용할 때 @EnableAspectJAutoProxy(proxyTargetClass = true) 설정을 확인해야 한다.

이제 새로운 API를 만들 때마다 일일이 권한 체크 로직을 작성할 필요 없이 @RequireRole 어노테이션을 추가하는 것만으로 간단하게 적용할 수 있게 되었다. 🚀