모르지 않다는 것은 아는것과 다르다.

Spring Security

AccessDesicionManager 와 AccessDecisionVoter

채마스 2022. 2. 28. 20:47

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