728x90
ProtectPointcutPostProcessor
- 메서드 방식의 인가처리를 위한 자원 및 권한 정보 설정 시 자원에 포인트 컷 표현식을 사용할 수 있도록 지원하는 클래스
- 빈 후처리기로서 스프링 초기화 과정에서 빈 들을 검사하여 빈이 가진 메소드 중에서 포인트 컷 표현식과 matching 되는 클래스 , 메서드,권한 정보를 MapBasedMethodSecurityMetadataSource에전달하여 인가처리가 되도록 제공되는 클래스
- DB 저장 방식
- Method 방식
- io.security.service.OrderService.order : ROLE_USER
- Pointcut 방식
- execution(* io.security.service.*Service.*(..)) : ROLE_USER
- Method 방식
- 설정 클래스에서 빈 생성 시 접근 제한자가package 범위로 되어 있기 때문에 리플렉션을 이용해 생성한다

동작과정

동작과정 - DB에서 정보를 읽어와 ProtectPointcutPostProcess로 읽어온다.

Bean 등록 - MethodResourcesFactoryBean이 Method, pointcut 두 가지 모두 읽어 올 수 있도록 코드 추가
-
@Slf4j public class MethodResourcesFactoryBean implements FactoryBean<LinkedHashMap<String, List<ConfigAttribute>>> { private SecurityResourceService securityResourceService; private String resourceType; private LinkedHashMap<String, List<ConfigAttribute>> resourcesMap; public void setResourceType(String resourceType) { this.resourceType = resourceType; } public void setSecurityResourceService(SecurityResourceService securityResourceService) { this.securityResourceService = securityResourceService; } public void init() { if ("method".equals(resourceType)) { resourcesMap = securityResourceService.getMethodResourceList(); } else if ("pointcut".equals(resourceType)) { resourcesMap = securityResourceService.getPointcutResourceList(); } else { log.error("resourceType must be 'method' or 'pointcut'"); } } public LinkedHashMap<String, List<ConfigAttribute>> getObject() { if (resourcesMap == null) { init(); } return resourcesMap; } @SuppressWarnings("rawtypes") public Class<LinkedHashMap> getObjectType() { return LinkedHashMap.class; } public boolean isSingleton() { return true; } }
-
- 이슈사항으로 인한 클래스 추가
-
@Slf4j public class ProtectPointcutPostProcessor implements BeanPostProcessor { private final Map<String, List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String, List<ConfigAttribute>>(); private final MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource; private final Set<PointcutExpression> pointCutExpressions = new LinkedHashSet<>(); private final PointcutParser parser; private final Set<String> processedBeans = new HashSet<>(); public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) { Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required"); this.mapBasedMethodSecurityMetadataSource = mapBasedMethodSecurityMetadataSource; Set<PointcutPrimitive> supportedPrimitives = new HashSet<>(3); supportedPrimitives.add(PointcutPrimitive.EXECUTION); supportedPrimitives.add(PointcutPrimitive.ARGS); supportedPrimitives.add(PointcutPrimitive.REFERENCE); parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives); } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (processedBeans.contains(beanName)) { return bean; } synchronized (processedBeans) { if (processedBeans.contains(beanName)) { return bean; } Method[] methods; try { methods = bean.getClass().getMethods(); } catch (Exception e) { throw new IllegalStateException(e.getMessage()); } for (Method method : methods) { for (PointcutExpression expression : pointCutExpressions) { if (attemptMatch(bean.getClass(), method, expression, beanName)) { break; } } } processedBeans.add(beanName); } return bean; } /** * 설정클래스에서 람다 형식으로 선언된 빈이 존재할 경우 에러가 발생하여 스프링 빈과 동일한 클래스를 생성하여 약간 수정함 * 아직 AspectJ 라이브러리에서 Fix 하지 못한 것으로 판단되지만 다른 원인이 존재하는지 계속 살펴보도록 함 */ private boolean attemptMatch(Class<?> targetClass, Method method, PointcutExpression expression, String beanName) { boolean matches; try { matches = expression.matchesMethodExecution(method).alwaysMatches(); if (matches) { List<ConfigAttribute> attr = pointcutMap.get(expression.getPointcutExpression()); if (log.isDebugEnabled()) { log.debug("AspectJ pointcut expression '" + expression.getPointcutExpression() + "' matches target class '" + targetClass.getName() + "' (bean ID '" + beanName + "') for method '" + method + "'; registering security configuration attribute '" + attr + "'"); } mapBasedMethodSecurityMetadataSource.addSecureMethod(targetClass, method, attr); } return matches; } catch (Exception e) { matches = false; } return matches; } public void setPointcutMap(Map<String, List<ConfigAttribute>> map) { Assert.notEmpty(map, "configAttributes cannot be empty"); for (String expression : map.keySet()) { List<ConfigAttribute> value = map.get(expression); addPointcut(expression, value); } } private void addPointcut(String pointcutExpression, List<ConfigAttribute> definition) { Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required"); Assert.notNull(definition, "A List of ConfigAttributes is required"); pointcutExpression = replaceBooleanOperators(pointcutExpression); pointcutMap.put(pointcutExpression, definition); pointCutExpressions.add(parser.parsePointcutExpression(pointcutExpression)); if (log.isDebugEnabled()) { log.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'"); } } private String replaceBooleanOperators(String pcExpr) { pcExpr = StringUtils.replace(pcExpr, " and ", " && "); pcExpr = StringUtils.replace(pcExpr, " or ", " || "); pcExpr = StringUtils.replace(pcExpr, " not ", " ! "); return pcExpr; } }
-
728x90
'스프링 시큐리티 > 실전프로젝트 - 인가 프로세스 DB 연동 서비스 계층 구현' 카테고리의 다른 글
| ch08. ProxyFactory 를 활용한 실시간 메소드 보안 구현 (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 |