본문 바로가기
Spring/Spring Security

SpringSecurity 인가 아키텍쳐 - 메서드기반인가 관리자

by 롱싱싱 2024. 11. 10.

메서드기반인가 관리자 PreAuthorizeAuthorizationManager

  • 메서드 기반 인증된 사용자 및 특정 권한을 가진 사용자의 자원 접근 허용 여부를 결정
  • PreAuthorizeAuthorizationManager, PostAuthorizeAuthorizationManager, Jsr250AuthorizationManager, SecuredAuthorizationManager
  • 내부적으로 AOP방식에 의해 초기화 설정이 이루어지며 메서드 호출을 MethodIntercepter가 가로채어 처리함

메서드 권한 부여 초기화 과정

  1. 스프링은 초기화 시 생성되는 전체 빈을 검사하면서 빈이 가진 메소드 중에서 보안이 설정된 메소드가 있는지 탐색
    • ex) @PreAuthorize("hasAuthority('ROLE_USER"))
  2. 보안이 설정된 메소드가 있다면 스프링은 그 빈의 프록시 객체를 자동으로 생성 (기본적으로 Cglib 방식으로 생성한다) 
  3. 보안이 설정된 메소드에는 인가처리 기능을 하는 Advice 를 등록
  4. 스프링은 빈 참조시 실제 빈이 아닌 프록시 빈 객체를 참조하도록 처리
  5. 초기화 과정이 종료
  6. 사용자는 프록시 객체를 통해 메소드를 호출하게 되고 프록시 객체는 Advice 가 등록된 메서드가 있다면 호출하여 작동
  7. Advice 는 메소드 진입 전 인가 처리를 하게 되고 인가처리가 승인되면 실제 객체의 메소드를 호출하게 되고 인가처리가 거부되면 예외가 발생하고 메소드 진입이 실패

메서드 인터셉터 구조

  • AuthorizationManagerBeforeMethodInterceptor - 지정된 AuthorizationManager를 사용해서 Authentication이 보안 메서드를 호출할 수 있는지 여부 결정
  • AuthorizationManagerAfterMethodInterceptor - 지정된 AuthorizationManager를 사용해서 Authentication이 보안 메서드 반환 결과에 접근할 수 있는지 여부 결정 (@PostAuthorize)
  • PreFilterAuthorizationMethodInterceptor - @PreFilter어노테이션에서 표현식을 평가하여 메소드 인자 필터링
  • PostFilterAuthorizationMethodInterceptor - @PostFilter어노테이션에서 표현식을 평가하여 보안 메서드에서 반환 객체를 필터링

CustomAuthorizationManager구현

 

메서드 보안 인터셉터 순서

public enum AuthorizationInterceptorsOrder {
    FIRST(Integer.MIN_VALUE),
    PRE_FILTER, // 100
    PRE_AUTHORIZE, // 200
    SECURED, // 300
    JSR250, // 400
    POST_AUTHORIZE, // 500

     POST_FILTER, // 600
    LAST(Integer.MAX_VALUE);
}

스프링 시큐리티보다 다른 어드바이스가 실행되어야 할 경우 order=0과 같이 순서를 지정해야한다. ex)@EnableTransactionManagement(order=0) - 트랜잭션이 열린 상태에서 보안 검사가 이루어짐

AuthorizationInterceptorsOrder를 사용하여 인터셉터 간 순서를 지정할 수 있다.

 

SecurityConfig설정할 때 @EnableMethodSecurity(prePostEnable=false) 설정해야함

@EnableMethodSecurity(prePostEnabled = false)
@Configuration
public class MethodSecurityConfig {

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public Advisor preAuthorize(){
        return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(new MyPreAuthorizationManager());
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public Advisor postAuthorize(){
        return AuthorizationManagerAfterMethodInterceptor.postAuthorize(new MyPostAuthorizationManager());
    }
}

 

MyPreAuthorizationManager

public class MyPreAuthorizationManager implements AuthorizationManager<MethodInvocation> {
    @Override
    public void verify(Supplier<Authentication> authentication, MethodInvocation object) {
        AuthorizationManager.super.verify(authentication, object);
    }

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation object) {
        Authentication auth = authentication.get();
        if(auth instanceof AnonymousAuthenticationToken)return new AuthorizationDecision(false);

        return new AuthorizationDecision(auth.isAuthenticated());
    }
}

 

MyPostAuthorizationManager

public class MyPostAuthorizationManager implements AuthorizationManager<MethodInvocationResult> {
    @Override
    public void verify(Supplier<Authentication> authentication, MethodInvocationResult object) {
        AuthorizationManager.super.verify(authentication, object);
    }

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocationResult object) {
        Authentication auth = authentication.get();
        if(auth instanceof AnonymousAuthenticationToken)return new AuthorizationDecision(false);

        AccountDTO account = (AccountDTO) object.getResult();
        boolean isGranted = account.getUsername().equals(auth.getName());

        return new AuthorizationDecision(isGranted);


    }
}

 


포인트 컷으로 구현하기

 

어노테이션을 사용하지 않고 메소드 기반 인가 관리자를 구현할 수 있다.

implementation group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: '3.2.2'

 

 

 


AOP 메서드 보안 구현하기 MethodInterceptor, Pointcut, Advisor

AOP 요소

Advisor

  • AOP Advice와 Advice 적용 가능성을 결정하는 포인트컷을 가진 기본 인터페이스

MethodInterceptor(Advice)

  • 대상 객체를 호출하기 전과 후에 추가 작업을 수행하기 위한 인터페이스 -> 수행 이후 대상 객체 조인포인트 호출을 위해 Joinpoint.proceed()를 호출

Pointcut

  • AOP에서 Advice가 적용될 메소드나 클래스를 정의하는 것으로서 어드바이스가 실행되어야 하는 적용지점이나 조건 지정
  • ClassFilter와 MethodMatcher를 사용해서 어떤 클래스 및 어떤 메서드에 Advice를 적용할지 결정

AOP적용 순서

  1. CustomMethodInterceptor 를 생성하고 메소드 보안 검사를 수행할 AuthorizationManager 를 CustomMethodInterceptor 에 전달한다
  2. CustomPointcut 을 생성하고 프록시 대상 클래스와 대상 메서드를 결정할 수 있도록 포인트컷 표현식을 정의한다
  3. DefaultPointcutAdvisor 을 생성하고 CustomMethodInterceptor 와 CustomPointcut 을 DefaultPointcutAdvisor 에 전달한다
  4. 서비스를 호출하면 Pointcut 으로부터 대상 클래스와 대상 메서드에 등록된 MethodInterceptor 를 탐색하고 결정되면 이를 호출하여 AOP 를 수행한다