Spring

AOP- Security check

MDanderson 2023. 11. 9. 20:37

@Target(ElementType.METHOD):
@Target 메타 어노테이션은 정의된 어노테이션(@SecurityCheck)이 적용될 수 있는 Java 요소를 지정합니다. 여기서 ElementType.METHOD는 이 어노테이션이 메소드 선언에만 사용될 수 있음을 의미합니다. 다른 ElementType으로는 클래스, 필드, 매개변수 등이 있습니다.


@Retention(RetentionPolicy.RUNTIME):
@Retention 메타 어노테이션은 어노테이션 정보가 어느 시점까지 유지될 것인지를 명시합니다. RetentionPolicy.RUNTIME은 어노테이션 정보가 런타임에도 유지되어야 함을 나타내며, 이는 리플렉션을 통해 해당 정보를 런타임에서도 접근할 수 있음을 의미합니다. 다른 정책으로는 소스 코드(RetentionPolicy.SOURCE) 또는 클래스 파일(RetentionPolicy.CLASS)에만 유지되는 것이 있습니다.


@interface:
이는 사용자 정의 어노테이션을 선언할 때 사용하는 키워드입니다. @interface를 사용하면 Java 컴파일러에게 이 인터페이스가 어노테이션 정의임을 알립니다.


UserType value() default UserType.AUTHENTICATED;:
이 부분은 @SecurityCheck 어노테이션에 사용할 속성을 정의합니다. UserType은 위에서 정의한 열거형(enum)으로, MANAGER, CAFE, AUTHENTICATED, NOT_AUTHENTICATED의 네 가지 값을 가질 수 있습니다.


value() 메소드는 어노테이션을 사용할 때 값을 설정할 수 있도록 합니다. 예를 들어, @SecurityCheck(UserType.MANAGER)는 MANAGER가 필요한 보안 검사를 나타냅니다.


default UserType.AUTHENTICATED는 @SecurityCheck 어노테이션에 구체적인 값이 제공되지 않았을 때 사용할 기본값을 지정합니다. 여기서는 기본값으로 UserType.AUTHENTICATED가 사용됩니다. 즉, 특별한 값을 지정하지 않으면, 인증된 사용자에 대한 보안 검사가 기본적으로 적용됩니다.


이렇게 정의된 @SecurityCheck 어노테이션은 메소드에 보안 검사를 적용하고자 할 때 사용되며, AOP의 포인트컷을 정의하는 데 이용될 수 있습니다. 해당 어노테이션이 적용된 메소드는 AOP 어드바이스에 의해 실행 전에 특정 보안 검사를 수행하도록 설정할 수 있습니다.

 

 

@Aspect:
@Aspect는 클래스가 Aspect를 정의하고 있다는 것을 나타냅니다. Aspect는 특정 "관심사(cross-cutting concern)"를 모듈화한 것으로, 이 경우에는 보안 검사입니다. Aspect는 애플리케이션의 여러 부분에 걸쳐 사용되는 로직(예: 로깅, 트랜잭션 관리, 보안)을 한 곳에 모아 관리할 수 있게 해줍니다.


@Component:
@Component는 클래스를 Spring의 Bean으로 등록하는 데 사용됩니다. 이는 Spring이 이 클래스의 인스턴스를 자동으로 생성하고 관리하도록 만듭니다. AOP Aspect도 Spring 컨테이너에 의해 관리되는 Bean 중 하나여야 합니다.


@Pointcut:
@Pointcut은 어드바이스(Advice, Aspect가 적용되는 코드)가 적용될 위치, 즉 조인 포인트(Join point, Aspect가 적용될 수 있는 지점)를 정의합니다. 여기서는 @SecurityCheck 어노테이션이 적용된 모든 메소드에 대한 포인트컷을 선언하고 있습니다.


@Around:
@Around는 조인 포인트 전후로 코드를 실행할 수 있는 어드바이스를 정의합니다. 이는 대상 메소드가 실행되기 전과 후에 추가적인 로직을 실행할 수 있게 합니다. @Around 어드바이스는 ProceedingJoinPoint를 매개변수로 받아, joinPoint.proceed()를 호출하여 대상 메소드의 실행을 진행하거나, 보안 검사를 통과하지 못하면 예외를 발생시켜 메소드 실행을 중단합니다.
이 코드에서는 HTTP 요청 헤더에서 토큰을 추출하여 사용자의 인증 상태를 검사하는 로직이 포함되어 있습니다. 사용자가 특정 역할(관리자, 카페 소유자 등)에 부합하거나 인증되었을 경우에만 메소드 실행을 허용하고, 그렇지 않으면 SecurityException을 발생시켜 접근을 거부합니다.

이런 식으로 AOP를 사용하면, 보안 로직을 비즈니스 로직에서 분리하여 중복을 줄이고, 유지보수성을 향상시킬 수 있습니다. 또한, 코드의 가독성을 높이고, 보안 로직을 애플리케이션 전반에 일관되게 적용할 수 있습니다.

 

 

joinPoint.proceed(); 부분은 AOP의 핵심 기능 중 하나인 어드바이스(Advice) 내에서 사용됩니다. ProceedingJoinPoint 객체의 proceed() 메소드를 호출하는 것은 실제로 타겟 메소드(즉, AOP가 적용되는 메소드)를 실행하는 명령입니다.

@Around 어드바이스에서 proceed() 메소드를 호출할 때, 다음과 같은 일이 발생합니다:
1.타겟 메소드 호출: AOP 프록시는 proceed() 메소드 호출을 통해 실제 타겟 메소드를 실행합니다. 타겟 메소드가 반환하는 값을 result 변수에 저장합니다.


2.메소드 실행 후 처리: 타겟 메소드 실행 후, proceed() 메소드는 타겟 메소드가 반환한 객체를 리턴합니다. 이 값을 result에 할당하고, 이후 코드에서 추가적인 처리를 할 수 있습니다.


3.결과 반환: 마지막으로, result 객체를 리턴하여 타겟 메소드의 결과를 호출자에게 전달합니다. 이는 AOP가 적용된 메소드가 일반적인 메소드처럼 작동하고 결과를 반환하는 것처럼 보이게 합니다.

@Around 어드바이스를 사용할 때는 proceed() 메소드 호출 전후로 추가 로직을 삽입할 수 있습니다. 이는 메소드 실행 전에 사전 검사를 수행하거나, 실행 후에 사후 처리를 수행하는 데 사용될 수 있습니다.

다음은 proceed() 메소드를 사용하는 과정의 예시입니다:

이렇게 proceed() 메소드는 AOP를 사용하여 비즈니스 로직에 영향을 주지 않으면서도 추가적인 기능을 수행할 수 있도록 해줍니다.

return joinPoint.proceed(); 구문은 @Around 어드바이스 안에서 타겟 메소드(즉, 보안 검사를 거쳐 실행되어야 하는 메소드)를 실행하고 그 결과를 호출자에게 반환합니다.

joinPoint.proceed(); 메소드는 AOP 프록시를 통해 실제 타겟 메소드를 호출하고, 타겟 메소드로부터 반환된 결과를 가져옵니다. 이 결과는 타겟 메소드의 반환 타입에 따라 다양할 수 있으며, Object 타입으로 처리됩니다. 이후에 return 문을 사용하여 이 결과를 메소드 호출자에게 다시 반환합니다.

위 코드에서 보안 조건을 확인한 후 조건이 충족될 경우 (if 문 안에서), 타겟 메소드를 실행하고 그 결과를 반환하고 있습니다. 이는 타겟 메소드의 실행을 주변 로직(여기서는 보안 검사)에 의해 감싸는 것으로, AOP에서 매우 일반적인 패턴입니다.

조건이 충족되지 않을 경우 (else 부분, 여기서는 생략되어 있지만), 보안 예외(SecurityException)가 발생하여 타겟 메소드가 실행되지 않고, 호출자는 예외를 받게 됩니다.

return joinPoint.proceed(); 구문을 사용함으로써, 타겟 메소드의 실행과 결과 반환을 한 줄의 코드로 간결하게 처리할 수 있습니다. 그렇게 함으로써, 타겟 메소드가 실제로 호출되었음을 명시하고, 그 결과가 어드바이스를 호출한 측에 정확히 전달되도록 합니다.