스프링 시큐리티/실전프로젝트 - 인가 프로세스 DB 연동 서비스 계층 구현

ch02. AOP Method 기반 DB 연동 - 주요 아키텍처 이해

webmaster 2022. 1. 25. 12:53
728x90

인가 처리를 위한 초기화 과정과 진행

  • 초기화 과정
    1. 초기화 시 전체 빈을 검사하면서 보안이 설정된 메소드가 있는지 탐색
    2. 빈의 프록시 객체를 생성( Spring이 자동 생성)
    3. 보안 메서드에인가처리(권한 심사) 기능을 하는 Advice를등록
    4. 참조시 실제 빈이 아닌 프록시 빈 객체를 참조
    5. Key: 메서드, value: 권한을 등록한다
  • 진행과정
    1. 메소드 호출 시 프록시 객체를 통해 메소드를 호출
    2. Advice가 등록되어 있다면 Advice를 작동하게 하여 인가 처리
    3. 권한 심사 통과하면 실제 빈의 메서드를

인가 처리를 위한 초기화 과정

동작과정

  • DefaultAdvisorAutoProxyCreator가 메소드를 찾아 그 빈의 Proxy 객체를 생성한다.
  • 어떤 과정의 통해 빈을 찾는지?
    • MethodSecurityMetadataSourceAdvisor 메소드를 통해 검색하게 된다.
      1. MethodSecurityMetadataSourcePointcut 이 PointCut이 설정된 빈을 찾는다.
      2. MethodSecurityInterceptor를 통해 보안 메서드로 advice로 등록한다
    • public class MethodSecurityMetadataSourceAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
          private transient MethodSecurityMetadataSource attributeSource;
          private transient MethodInterceptor interceptor;
          private final Pointcut pointcut = new MethodSecurityMetadataSourceAdvisor.MethodSecurityMetadataSourcePointcut();
          private BeanFactory beanFactory;
          private final String adviceBeanName;
          private final String metadataSourceBeanName;
          private transient volatile Object adviceMonitor = new Object();
      
          public MethodSecurityMetadataSourceAdvisor(String adviceBeanName, MethodSecurityMetadataSource attributeSource, String attributeSourceBeanName) {
              Assert.notNull(adviceBeanName, "The adviceBeanName cannot be null");
              Assert.notNull(attributeSource, "The attributeSource cannot be null");
              Assert.notNull(attributeSourceBeanName, "The attributeSourceBeanName cannot be null");
              this.adviceBeanName = adviceBeanName;
              this.attributeSource = attributeSource;
              this.metadataSourceBeanName = attributeSourceBeanName;
          }
      
          public Pointcut getPointcut() {
              return this.pointcut;
          }
      
          public Advice getAdvice() {
              synchronized(this.adviceMonitor) {
                  if (this.interceptor == null) {
                      Assert.notNull(this.adviceBeanName, "'adviceBeanName' must be set for use with bean factory lookup.");
                      Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
                      this.interceptor = (MethodInterceptor)this.beanFactory.getBean(this.adviceBeanName, MethodInterceptor.class);
                  }
      
                  return this.interceptor;
              }
          }
      
          public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
              this.beanFactory = beanFactory;
          }
      
          private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
              ois.defaultReadObject();
              this.adviceMonitor = new Object();
              this.attributeSource = (MethodSecurityMetadataSource)this.beanFactory.getBean(this.metadataSourceBeanName, MethodSecurityMetadataSource.class);
          }
      
          class MethodSecurityMetadataSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
              MethodSecurityMetadataSourcePointcut() {
              }
      
              public boolean matches(Method m, Class<?> targetClass) {
                  MethodSecurityMetadataSource source = MethodSecurityMetadataSourceAdvisor.this.attributeSource;
                  return !CollectionUtils.isEmpty(source.getAttributes(m, targetClass));
              }
          }
      }

동작 과정

동작 과정

  • 사용자가 Order메서드를 호출 -> 실제 Bean이 아닌 Proxy가 호출이 된다.
  • Advice에 등록돼 있는지를 확인한 뒤, 등록되어있다면 MethodSecurityInterceptor가 인가처리를 한다.
  • 인가 처리가 성공 -> 실제 객체 메서드 호출
  • 인가 처리가 실패 -> 메소드 접근 차단(AccessDeniedException)
  • AOP 이해

 

728x90