인프런 커뮤니티 질문&답변

henry_hong님의 프로필 이미지
henry_hong

작성한 질문수

스프링 시큐리티

6) AOP Method 기반 DB 연동 - MapBasedSecurityMetadataSource (3)

원래 Method 방식은 권한계층이 적용되지 않는건가요 ?

작성

·

255

0

Url 방식은 정삭적으로 권한계층에 맞게 manager 권한을 요청하면 manager, admin은 접근 가능하지만, user는 접근 불가하게 설정되는 반면, Method방식은 manager 권한을 요청하면 manager을 제외한 user와 admin 은 접근이 불가능합니다. 왜 이런걸까요 ?

답변 2

4

정수원님의 프로필 이미지
정수원
지식공유자

네 

스프링 시큐리티는 Method 권한를 초기화 할 때 AffirmativeBased 와 AccessDecisionVoter 클래스를 기본적으로 구성하고 있습니다.

GlobalMethodSecurityConfiguration 클래스에 보시면 아래와 같은 메소드를 정의하고 있습니다.

protected AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
if (prePostEnabled()) {
ExpressionBasedPreInvocationAdvice expressionAdvice =
new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler());
decisionVoters
.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
}
if (jsr250Enabled()) {
decisionVoters.add(new Jsr250Voter());
}
RoleVoter roleVoter = new RoleVoter();
GrantedAuthorityDefaults grantedAuthorityDefaults =
getSingleBeanOrNull(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
roleVoter.setRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
decisionVoters.add(roleVoter);
decisionVoters.add(new AuthenticatedVoter());
return new AffirmativeBased(decisionVoters);
}

즉 AccessDecisionManager 의 구현체인 AffirmativeBased 를 생성하는 구문인데 여러가지 Voter 객체들을 생성하고 있는데 중간쯤에 보시면 RoleVoter 객체를 생성하고 있습니다.

근데 RoleVoter 는 권한 계층이 적용되지 않는 단순한 ROLE 만을 검사하는 Voter 클래스입니다.

그래서 권한 계층에 따른 리소스 접근을 적용하고자 할 때는 아래와 같은 Voter 클래스를 생성해서 추가해 주어야 합니다.

@Bean
public AccessDecisionVoter<? extends Object> roleVoter() {

RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy());
return roleHierarchyVoter;
}

@Bean
public RoleHierarchyImpl roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
return roleHierarchy;
}

그래서 위의 accessDecisionManager() 메소드를 Override 해서 RoleHierarchyVoter 를 추가해 주면 됩니다.

대략 다음과 같이 구현하시면 될 것 같습니다.

@Bean
public CustomMethodSecurityInterceptor customMethodSecurityInterceptor(MapBasedMethodSecurityMetadataSource methodSecurityMetadataSource) {
CustomMethodSecurityInterceptor customMethodSecurityInterceptor = new CustomMethodSecurityInterceptor();
customMethodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
customMethodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager());
customMethodSecurityInterceptor.setSecurityMetadataSource(methodSecurityMetadataSource);
RunAsManager runAsManager = runAsManager();
if (runAsManager != null) {
customMethodSecurityInterceptor.setRunAsManager(runAsManager);
}

return customMethodSecurityInterceptor;
}
@Override
protected AccessDecisionManager accessDecisionManager() {
AffirmativeBased affirmativeBased = (AffirmativeBased)super.accessDecisionManager();
List<AccessDecisionVoter<?>> decisionVoters = affirmativeBased.getDecisionVoters();
for(AccessDecisionVoter accessDecisionVoter : decisionVoters){
if(accessDecisionVoter instanceof RoleVoter){
decisionVoters.remove(accessDecisionVoter);
}
}
decisionVoters.add(0,roleVoter());
return affirmativeBased;
}

코드는 그리 복잡하지 않습니다.

먼저 CustomMethodSecurityInterceptor 빈 객체를 생성할 때 AccessDecisionManager  를 설정해 주어야 합니다.

customMethodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());

그리고 아래 accessDecisionManager() 를 정의하는 구문에서 코드를 보시면 super.accessDecisionManager() 를 호출해서 기본 Voter 객체들이 담겨져 있는 List<AccessDecisionVoter<?>> decisionVoters 속성을 참조해서 기존의 RoleVoter 객체는 삭제하고 RoleHierarchyVoter 객체를 List<AccessDecisionVoter<?>> decisionVoters 의 처음 위치에 저장합니다.

그러면 최종적으로 AffirmativeBased 는 RoleHierarchyVoter  를 가진 상태가 되고 이것을 customMethodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager()) 해서 설정하면 Method 방식도 권한계층의 Voter 가 적용된 인가프로세스를 진행하게 됩니다.

실행화면입니다.

위에 보시면 리소스에 필요한 권한은 ROLE_MANAGER 인데 사용자는 ROLE_ADMIN 권한을 가지고 있습니다.

그리고 AccessDecisionManager 의 decisionVoters 에는 RoleHiearchyVoter 객체가 0번째로 위치해 있는 것을 확인할 수 있습니다.

원래는 RoleVoter 가 있었는데 초기화 시 삭제했기 때문에 없습니다.

그래서 ROLE_ADMIN 권한의 사용자는 ROLE_MANAGER 로 매핑된 리소스에 접근할 수 있게 됩니다.

결론적으로 Url 방식이든 Method 방식이든 상관없이 Voter 정책을 어떻게 하느냐에 따라 인가처리가 이루어지는 것임을 알 수 있습니다.

1

henry_hong님의 프로필 이미지
henry_hong
질문자

이전에 학습한 내용인데도 적용하고자 할 때에는 막히는 부분이 생기는군요.. 정확한 설명 감사합니다.

henry_hong님의 프로필 이미지
henry_hong

작성한 질문수

질문하기