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

Spring Security

Voter 커스텀 하기

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

개요

  • Voter 를 커스텀해서 IP 를 검증하는 로직을 추가할 수 있다.





Voter custom 하기

  • 특정한 IP 만 접근이 가능하도록 하고 싶다면, IP 를 심의하는 Voter 추가하면 된다.

  • AccessDecisionManager 의 구현체중 AffirmativeBased 가 기본적략이기 때문에 Voter 중 하나만 통과되도 허용된다.
  • 또한 나는 직접 만든 IpAddressVoter 에서 허용되지 않으면, 바로 자원접근을 거부하고 싶다.
  • 그렇기 때문에 아래와 같은 규칙이 필요하다.
    • AffirmativeBased 에서 직접만든 IpAddressVoter 를 우선적으로 체크해야 되기 때문에 가장 상위에 위치시켜서 먼저 검사하도록 설정해야 한다.
    • 허용된 IP의 경우 ACCESS_GRANTED 가 아닌 ACCESS_ABSTAIN 를 리턴해서 추가 심의를 계속 진행하도록 한다.
    • 허용되지 않은 IP의 경우 ACCESS_DENIED 가 아닌 AccessDeniedException 를 던져서 최종 자원 접근을 거부시키는 것이다. -> 만약 ACCESS_DENIED 이면 다음 Voter 를 검사하기 때문이다.

코드 구현

public class IpAddressVoter implements AccessDecisionVoter<Object> {

    private SecurityResourceService securityResourceService;

    public IpAddressVoter(SecurityResourceService securityResourceService) {
        this.securityResourceService = securityResourceService;
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return (attribute.getAttribute() != null);
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

    @Override
    public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> configList) {

        if (!(authentication.getDetails() instanceof WebAuthenticationDetails)) {
            return ACCESS_DENIED;
        }

        WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
        String address = details.getRemoteAddress();
        List<String> accessIpList = securityResourceService.getAccessIpList();

        int result = ACCESS_DENIED;

        for (String ipAddress : accessIpList) {

            if (address.equals(ipAddress)) {
                return ACCESS_GRANTED;
            }
        }

        if(result == ACCESS_DENIED){
            throw new AccessDeniedException("Invalid ipAddress can not accessed");
        }

        return result;
    }
}
  • AccessDecisionVoter 클래스를 구현하고 있다.
  • 위와 같이 vote 메소드에서 위에서 설정한 규칙을 구현한다.





Security Config 파일 설정

    private AccessDecisionManager affirmativeBased() {
        AffirmativeBased affirmativeBased = new AffirmativeBased(getAccessDecisionVoters());
        return affirmativeBased;
    }

    private List<AccessDecisionVoter<?>> getAccessDecisionVoters() {

        List<AccessDecisionVoter<? extends Object>> accessDecisionVoters = new ArrayList<>();
        accessDecisionVoters.add(new IpAddressVoter(securityResourceService));
        accessDecisionVoters.add(roleVoter());

        return accessDecisionVoters;
    }
  • AccessDecisionManager 의 디폴트 구현체인 AffirmativeBased 는 하나만 통과해도 전부 통과 시키는 전략이다.
  • 그렇기 때문에 Voter 중에서 가장먼저 IpAddressVoter 를 검사해야 IP 검사를 정상적으로 처리할 수 있다.
  • 그렇기 때문에 accessDecisionVoters 에 가장 첫번째로 IpAddressVoter 를 위치시킨다.




REFERENCES

  • 정수원님의 스프링 시큐리티

'Spring Security' 카테고리의 다른 글

URL 시큐리티 프로세스 커스텀  (0) 2022.02.28
권한 계층 적용하기  (0) 2022.02.28
@AuthenticationPrincipal  (0) 2022.02.28
메소드 시큐리티  (0) 2022.02.28
Custom DSL 적용  (0) 2022.02.28