Interceptor + AOP

기 원·2025년 4월 20일

Java를 Spring 처럼!

목록 보기
4/5

긴급코딩! - Interceptor + AOP

💡 우리의 목표는?

Admin API 접근 시 인터셉터에서 인증, AOP에서 로깅 처리

목표 시나리오

  • /admin/** 경로에 접근 할때:
    1. 인터셉터가 JWT 토큰을 검사하고, ADMIN 관한이 아니면 거부
    1. AOP가 요청 및 응답 내용을 로깅

Step 1. Interceptor - 인증 처리

1. AdminInterceptor.java


@Component
public class AdminInterceptor implements HandlerInterceptor {


    private final JwtProvider jwtProvider;

	// 생성자 주입 방식으로 JwtProvider 의존성 주입!
    public AdminInterceptor(JwtProvider jwtProvider) {
        this.jwtProvider = jwtProvider; 
    }

	// 컨트롤러 실행 전 요청을 가로채는 메서드(인터셉트!)
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {

		// 요청에서 토큰 추출
        String token = jwtProvider.resolveToken(request);
        
        // 토큰이 없거나 유효하지 않으면 401 Unauthorized 응답
        if (token == null || !jwtProvider.validateToken(token)) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value()); // 인증 실패
            return false; // 컨트롤러로 진입하지 않음
        }

		// 토큰에서 역할 정보 추출
        String role = jwtProvider.getRole(token);
        
        // 역할이 ADMIN이 아니면 403 Forbidden
        if (!"ADMIN".equals(role)) {
            response.setStatus(HttpStatus.FORBIDDEN.value()); // 인가 실패
            return false;
        }

		// 모든 조건을 통과하면 true 반환 → 컨트롤러 실행 허용
        return true;
    }
}

2. WebConfig.java

@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final AdminInterceptor adminInterceptor;

    public WebConfig(AdminInterceptor adminInterceptor) {
        this.adminInterceptor = adminInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    	// "/admin/**" 경로에 대해서만 adminInterceptor를 적용
        registry.addInterceptor(adminInterceptor)
                .addPathPatterns("/admin/**");
    }
}

Step 2. AOP - 요청/응답 로깅

1. AdminLoggingAspect.java

@Aspect // AOP 클래스임을 나타냄
@Component
@Slf4j // 로그 출력용 롬복 어노테이션 (log.info 사용 가능)
public class AdminLoggingAspect {

    // Pointcut 설정: admin 하위 패키지의 모든 메서드에 적용
    @Pointcut("execution(* com.example.controller.admin..*(..))")
    public void adminMethods() {}

    // 어드민 메서드 실행 전후로 로그를 남김
    @Around("adminMethods()")
    public Object logAdminRequest(ProceedingJoinPoint joinPoint) throws Throwable {

        // 현재 요청 객체 가져오기 (RequestContextHolder는 AOP 내에서 HttpServletRequest 접근 가능하게 함)
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        // URI 정보 및 요청자 ID 추출
        String uri = request.getRequestURI();
        String userId = request.getHeader("userId"); // 예: 헤더에서 userId 가져오기

        // 요청 로그 출력 (args는 메서드 파라미터 배열)
        log.info("어드민 요청 - userId: {}, URI: {}, request: {}", userId, uri, Arrays.toString(joinPoint.getArgs()));

        // 원래의 컨트롤러 메서드 실행
        Object result = joinPoint.proceed();

        // 응답 로그 출력
        log.info("어드민 응답 - userId: {}, URI: {}, response: {}", userId, uri, result);

        return result;
    }
}

Step 3. 테스트용 Admin Controller

1. UserAdminController.java

@RestController
@RequestMapping("/admin/users")
public class UserAdminController {

    // 어드민 권한이 있어야만 접근 가능한 API
    @PatchMapping("/{userId}")
    public ResponseEntity<String> changeUserRole(@PathVariable Long userId, @RequestBody RoleUpdateRequest request) {

        return ResponseEntity.ok("변경 완료");
    }
}

마무리

[요청] → Interceptor (인증 확인)
               ↓
     통과하면 AOP 진입 (로깅)
               ↓
     컨트롤러 실행 (ex. changeUserRole)
               ↓
     AOP 종료 로그
               ↓
[응답 반환]
기능구현 위치역할
권한 검사Interceptor인증 (사전 처리)
로그 기록AOP로깅 (사후 처리 포함)
관리자 API 예시UserAdminController테스트용 컨트롤러
profile
노력하고 있다니까요?

1개의 댓글

comment-user-thumbnail
2025년 4월 20일

선댓글 달겠습니다 휴일에 글이 올라오다니 너무 감사드립니다

답글 달기