728x90
개선점
- 메서드 보안은 스프링 시큐리티 초기화 시점에 보안 적용 대상 빈의 프록시 생성 및 어드바이스 적용이 이루어짐
- DB에 자원을 실시간으로 업데이트하더라도AOP 가 바로 적용되지 않음
- 초기화 과정에 프락시 객체가 생기고 advice를 생성하기 때문에
보안 메서드 실시간 적용 처리 과정
- 메소드 보안 최초 설정 시 대상 빈의 프록시 객체 생성하고 메소드에 Advice 등록하여 AOP 적용
-
MapBasedMethodSecurityMetadataSource에 자원 및 권한 정보 전달
-
DefaultSingletonBeanRegistry로실제 빈을 삭제하고 프록시 객체를 빈 참조로 등록한다
-
보안이 적용된 메서드 호출 시 Advice 가 작동한다
-
메소드 보안 해제 시 메서드에등록된 Advice를 제거한다
-
메서드 보안 재 설정 시 메서드에등록된 Advice를Advice를 다시 등록한다

- Interceptor 빈 추가
- CustomMethodSecurityInterceptor
-
public class CustomMethodSecurityInterceptor extends AbstractSecurityInterceptor implements MethodInterceptor { private MethodSecurityMetadataSource securityMetadataSource; public Class<?> getSecureObjectClass() { return MethodInvocation.class; } public Object invoke(MethodInvocation mi) throws Throwable { InterceptorStatusToken token = super.beforeInvocation(mi); Object result; try { result = mi.proceed(); } finally { super.finallyInvocation(token); } return super.afterInvocation(token, result); } public MethodSecurityMetadataSource getSecurityMetadataSource() { return this.securityMetadataSource; } public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public void setSecurityMetadataSource(MethodSecurityMetadataSource newSource) { this.securityMetadataSource = newSource; } }
-
- MethodService 추가
- addMethodSecured : 프록시 추가
- removeMethodSecured : 프록시 제거
-
@Slf4j @Component public class MethodSecurityService { private MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource; private AnnotationConfigServletWebServerApplicationContext applicationContext; private CustomMethodSecurityInterceptor methodSecurityInterceptor; private Map<String, Object> proxyMap = new HashMap<>(); private Map<String, ProxyFactory> advisedMap = new HashMap<>(); private Map<String, Object> targetMap = new HashMap<>(); public MethodSecurityService(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource, AnnotationConfigServletWebServerApplicationContext applicationContext, CustomMethodSecurityInterceptor methodSecurityInterceptor) { this.mapBasedMethodSecurityMetadataSource = mapBasedMethodSecurityMetadataSource; this.applicationContext = applicationContext; this.methodSecurityInterceptor = methodSecurityInterceptor; } //DB에 실시간 정보를 제공할 떄 호출되는 메소드 public void addMethodSecured(String className, String roleName) throws Exception{ int lastDotIndex = className.lastIndexOf("."); String methodName = className.substring(lastDotIndex + 1); String typeName = className.substring(0, lastDotIndex); Class<?> type = ClassUtils.resolveClassName(typeName, ClassUtils.getDefaultClassLoader()); String beanName = type.getSimpleName().substring(0, 1).toLowerCase() + type.getSimpleName().substring(1); ProxyFactory proxyFactory = advisedMap.get(beanName); Object target = targetMap.get(beanName); if(proxyFactory == null){ proxyFactory = new ProxyFactory(); if(target == null) { proxyFactory.setTarget(type.getDeclaredConstructor().newInstance()); }else{ proxyFactory.setTarget(target); } proxyFactory.addAdvice(methodSecurityInterceptor); advisedMap.put(beanName, proxyFactory); }else{ int adviceIndex = proxyFactory.indexOf(methodSecurityInterceptor); if(adviceIndex == -1){ proxyFactory.addAdvice(methodSecurityInterceptor); } } Object proxy = proxyMap.get(beanName); if(proxy == null){ proxy = proxyFactory.getProxy(); proxyMap.put(beanName, proxy); List<ConfigAttribute> attr = Arrays.asList(new SecurityConfig(roleName)); mapBasedMethodSecurityMetadataSource.addSecureMethod(type,methodName, attr); DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry)applicationContext.getBeanFactory(); registry.destroySingleton(beanName); registry.registerSingleton(beanName, proxy); } } //실시간 삭제시 호출되는 메소드 public void removeMethodSecured(String className) throws Exception{ int lastDotIndex = className.lastIndexOf("."); String typeName = className.substring(0, lastDotIndex); Class<?> type = ClassUtils.resolveClassName(typeName, ClassUtils.getDefaultClassLoader()); String beanName = type.getSimpleName().substring(0, 1).toLowerCase() + type.getSimpleName().substring(1); Object newInstance = type.getDeclaredConstructor().newInstance(); DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry)applicationContext.getBeanFactory(); ProxyFactory proxyFactory = advisedMap.get(beanName); if(proxyFactory != null){ proxyFactory.removeAdvice(methodSecurityInterceptor); }else{ registry.destroySingleton(beanName); registry.registerSingleton(beanName, newInstance); targetMap.put(beanName,newInstance); } } }

Resource Controller에서 등록, 삭제시 메소드를 호출해 준다.
728x90
'스프링 시큐리티 > 실전프로젝트 - 인가 프로세스 DB 연동 서비스 계층 구현' 카테고리의 다른 글
| ch07. AOP Method 기반 DB 연동 - ProtectPointcutPostProcessor (0) | 2022.01.27 |
|---|---|
| ch06. AOP Method 기반 DB 연동 - MapBasedSecurityMetadataSource (3) (0) | 2022.01.26 |
| ch05. AOP Method 기반 DB 연동 - MapBasedSecurityMetadataSource (2) (0) | 2022.01.26 |
| ch04. AOP Method 기반 DB 연동 - MapBasedSecurityMetadataSource (1) (0) | 2022.01.26 |
| ch03. 어노테이션 권한 설정 - @PreAuthorize, @PostAuthorize, @Secured, @RolesAllowed (0) | 2022.01.25 |
