AccessDecisionManager
- 인증 정보, 요청정보, 권한정보를 이용해서 사용자의 자원접근에 대해서 Access Control 결정을 내리는 인터페이스이다.
- 여러개의 Voter 들을 가질 수 있다.
- Voter 들로부터 접근허용, 거부, 보류에 해당하는 각각의 값을 리턴받고 판단 및 결정한다.
- 구현체 3가지를 기본으로 제공한다.
- AffirmativeBased : 여러 Voter 중에 한명이라도 허용하면 허용, 기본전략
- ConsensusBased : 다수결
- UnanimousBased : 만장일치
- accessDecisionManager() 를 따로 구현하지 않으면, 기본적으로 AffirmativeBased() 를 사용한다.
- 아래와 같이 AffirmativeBased 코드에서 voter에 의해서 result 값이 생성된다.
public void decide(Authentication authentication, Object object,
Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
int deny = 0;
for (AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, object, configAttributes);
if (logger.isDebugEnabled()) {
logger.debug("Voter: " + voter + ", returned: " + result);
}
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
break;
}
}
// ... 이하 생략
}
AccessDecisionVoter
- Voter 들 마다 리소스에 접근할 자격이 있는지에 대한 판단을 심사하는 역할을 한다.
- Voter 가 권한 부여 과정에서 판단하는 자료
- Authentication - 인증 정보(user)
- FilterInvocation – 요청 정보 (antMatcher("/user"))
- ConfigAttributes - 권한 정보 (hasRole("USER")
- AccessDecisionVoter 는 3가지 역할을 한다.
- Authentication이 특정한 Object에 접근할 때 필요한 ConfigAttribute를 만족하는지 확인
- WebExpressionVoter : 웹 시큐리티에서 사용하는 기본 구현체, ROLE_XXX 일치하는지 확인
- RoleHierarchyVoter : 계층형 Role 지원
- 아래와 같이 계층을 설정할 수 있다.
public AccessDecisionManager accessDecisionManager() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setRoleHierarchy(roleHierarchy);
WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
webExpressionVoter.setExpressionHandler(handler);
List<AccessDecisionVoter<? extends Object>> voters = Arrays.asList(webExpressionVoter);
return new AffirmativeBased(voters);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers("/", "/info", "/account/**").permitAll()
.mvcMatchers("/admin").hasRole("ADMIN")
.mvcMatchers("/user").hasRole("USER")
.anyRequest().authenticated()
.accessDecisionManager(accessDecisionManager());
http.formLogin();
http.httpBasic();
}
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
여기서 roleHierarchy 를 설정해준다.- 그 다음 기존에 쓰는 handler 를 로드하고, setRoleHierarchy 를 해준다.
- 결정 방식은 아래와 같다.
- ACCESS_GRANTED : 접근허용(1)
- ACCESS_DENIED : 접근 거부(0)
- ACCESS_ABSTAIN : 접근 보류(-1)
AccessDecisionManager 와 AccessDecisionVoter 의 처리흐름
- FilterSecurityInterceptor 가 AccessDecisionManager 에게 (authentication, object, configAttributes) 정보와 함께, 인가 처리를 맡긴다.
- AccessDecisionManager 는 자신이 가지고 있는 여러 Voter 들에게도 (authentication, object, configAttributes) 를 넘겨준다.
- AccessDecisionVoter 가 판단 결과를 리턴해주고, AccessDecisionManager 최종 결과를 반환한다.
- 판단 결과가 ACCESS_DENIED 이면 AccessDeniedException 을 던진다.
- 당연하겠지만, AccessDecisionManager 인터페이스와 AccessDecisionVoter 인터페이스의 구현체를 직접만들어서, 판단 기준을 커스텀할 수 있다.
REFERENCES
- 백기선님의 스프링 시큐리티
- 정수원님의 스프링 시큐리티
'Spring Security' 카테고리의 다른 글
Custom Filter (0) | 2022.02.28 |
---|---|
RememberMeAuthenticationFilter (0) | 2022.02.28 |
ExceptionTranslationFilter,RequestCacheAwareFilter (0) | 2022.02.28 |
Security Filter (0) | 2022.02.28 |
CustomUserDetailService (0) | 2022.02.28 |