728x90
- 사용자 정의 AuthorizationManager 를 생성함으로 메서드 보안을 구현 가능
설정 클래스 정의
@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());
}
}
- @EnableMethodSecurity(prePostEnable=false) 설정 필요
- 시큐리티가 제공하는 클래스들을 비활성화
- true로 할 경우 @Pre/PostAuthorize, @Pre/PostFilter 총 4가지 클래스가 활성화되어 중복 검사를 하게 됨
사용자 정의 AuthorizationManager 구현
- 사용자 정의 AuthorizationManager는 여러 개 추가할 수 있으며 그럴 경우 체인 형태로 연결되어 각각 권한 검사를 하게 됨
public class MyPreAuthorizationManager implements AuthorizationManager<MethodInvocation>{
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation invocation) {
return new AuthorizationDecision(authentication.get().isAuthenticated());
}
}
public class MyPostAuthorizationManager implements AuthorizationManager<MethodInvocationResult>{
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocationResult result) {
Authentication auth = authentication.get();
if(auth instanceof AnonymousAuthenticationToken) return new AuthorizationDecision(false);
Account account = (Account) result.getResult();
boolean isGranted = account.getOwner().equals(authentication.get().getName());
return new AuthorizationDecision(isGranted)
}
}
- PostAuthorize에서 AuthorizataionManager<>의 제네릭 타입은 MethodInvocationResult
→ 결과값을 가지고 권한 심사를 해야하기 때문 - 인증 객체를 가지고와서 Anonymous(익명 사용자)라면 거부
- Result로 Account 객체를 반환 받아 owner가 같은지 다른지 비교하여 인가 결정
인터셉터 순서 지정
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);
}
- 메서드 보안 어노테이션에 대응하는 AOP 메소드 인터셉터들은 AOP 어드바이저 체인에서 특정 위치를 차지
- 구체적으로 @PreFilter 메소드 인터셉터의 순서는 100, @PreAuthorize의 순서는 200 등으로 설정
- 이것이 중요한 이유는 @EnableTransactionManagement와 같은 다른 AOP 기반 어노테이션들이 Integer.MAX_VALUE로 순서가 설정되어 있는데 기본적으로 이들은 어드바이저 체인의 끝에 위치
- 만약 스프링 시큐리티보다 먼저 다른 어드바이스가 실행 되어야 할 경우, 예를 들어 @Transactional 과 @PostAuthorize 가 함께 어노테이션 된 메소드가 있을 때 @PostAuthorize가 실행될 때 트랜잭션이 여전히 열려있어서 AccessDeniedException이 발생하면 롤백이 일어나게 할 수 있음
→ @PostAuthorize가 우선 순위를 가지기 때문에 @Transaction이 실행되지 않아 롤백이 일어나지 않음 - 따라서, 메소드 인가 어드바이스가 실행되기 전에 트랜잭션을 열기 위해서는 @EnableTransactionManagement의 순서 설정 필요
- @EnableTransactionManagement(order = 0)
- 위의 order = 0 설정은 트랜잭션 관리가 @PreFilter 이전에 실행되도록 하며 @Transactional 어노테이션이 적용된 메소드가 스프링 시큐리티의 @PostAuthorize 와 같은 보안 어노테이션보다 먼저 실행되어 트랜잭션이 열린 상태에서 보안 검사가 이루어지도록 설정 가능
→ 이러한 설정은 트랜잭션 관리와 보안 검사의 순서에 따른 의도하지 않은 사이드 이펙트를 방지 가능 - AuthorizationInterceptorsOrder를 사용하여 인터셉터 간 순서를 지정 가능
728x90
'Language > Spring Security' 카테고리의 다른 글
AOP 메서드 보안 구현 - MethodInterceptor, Pointcut, Advisor (0) | 2024.08.02 |
---|---|
포인트 컷 메서드 보안 구현 - AspectJExpressionPointcut / ComposablePointcout (0) | 2024.08.02 |
메서드 기반 인가 관리자 - PreAuthorizeAuthorizationManager 외 클래스 구조 이해 (0) | 2024.08.01 |
인가 설정 응용 - RequestMatcherDelegatingAuthorizationManager (0) | 2024.08.01 |
요청 기반 Custom AuthorizationManager 구현 (0) | 2024.08.01 |