spring/spring security

[Spring Security5] 권한 계층구조(roleHierarchy) 설정

moonsiri 2021. 8. 13. 11:16
728x90
반응형

1. roleHierarchy 설정

인가 관련해서는 AccessDecisionManager를 사용합니다. SecurityContextHolder에 저장되어있는 Authentication이 접근하는 리소스에 적절한 ROLE을 가지고 있는지 확인합니다. 확인하는 방법은 세 가지(AffirmativeBased, ConsensusBased, UnanimousBased)가 있는데 그중 AffrimativeBased(여러 Voter 중 하나라도 허용하면 허용)를 기본전략으로 사용합니다.

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Override
	public void configure(WebSecurity web) {
		...
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.addFilterAfter(getFilterSecurityInterceptor(), FilterSecurityInterceptor.class)
		...
	}

	@Bean(name = "filterSecurityInterceptor")
	public FilterSecurityInterceptor getFilterSecurityInterceptor() throws Exception {
		FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor();
		interceptor.setAccessDecisionManager(accessDecisionManager()); // AccessDecisionManager에 권한검사 위임
		interceptor.setSecurityMetadataSource(getReloadableFilterInvocationSecurityMetadataSource());

		return interceptor;
	}

	@Bean(name = "accessDecisionManager")
	public AffirmativeBased accessDecisionManager() {
		List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();

		RoleVoter roleVoter = new RoleHierarchyVoter(roleHierarchy());
		roleVoter.setRolePrefix("");

		decisionVoters.add(roleVoter); //security filter default

		AffirmativeBased affirm = new AffirmativeBased(decisionVoters);
		affirm.setAllowIfAllAbstainDecisions(false);
		return affirm;
	}

	@Bean
	public RoleHierarchy roleHierarchy() {
		RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
		roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER\nROLE_ADMIN > ROLE_DEV");
		return roleHierarchy;
	}
}

 

 

2. Security Tag에 계층구조 적용

ROLE_ADMIN 권한만 보유하고 있어도 ROLE_USER는 하위 권한이니 "ROLE_USER권한 보유" 문구가 노출되어야 합니다.

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<sec:authorize access="hasAnyRole('ROLE_USER')">ROLE_USER권한 보유</sec:authorize>

 

아래는 security tag 사용 시 권한 계층 구조 적용을 위한 설정입니다. 개인적으론 방법 1을 추천합니다.

 

방법 1)

accessDecisionManger의 decisionVoters list 순서 중요! security tag에서 권한을 체크할 때 voter의 순서대로 체크하는데 로직이 첫 번째 꺼에 없으면 두 번째 꺼는 무시하고 바로 리턴해버림

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Bean(name = "accessDecisionManager")
	public AffirmativeBased accessDecisionManager() {

        RoleVoter roleVoter = new RoleHierarchyVoter(roleHierarchy());
        roleVoter.setRolePrefix("");

        DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
        expressionHandler.setRoleHierarchy(roleHierarchy());
        WebExpressionVoter expressionVoter = new WebExpressionVoter();
        expressionVoter.setExpressionHandler(expressionHandler);

        List<AccessDecisionVoter<? extends Object>> decisionVoters = Arrays.asList(expressionVoter, roleVoter);

        AffirmativeBased affirm = new AffirmativeBased(decisionVoters);
        affirm.setAllowIfAllAbstainDecisions(false);
        return affirm;
	}

...
}

 

방법 2)

webSecurity에 expressionHandler 설정

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Override
	public void configure(WebSecurity web) {
		DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
		expressionHandler.setRoleHierarchy(roleHierarchy());
		web.expressionHandler(expressionHandler);
		...
	}
    
	...
}

 

728x90
반응형