[Spring Security] 아이피 접속 제한하기

식빵·2022년 9월 17일
1
post-custom-banner

이 시리즈에 나오는 모든 내용은 인프런 인터넷 강의 - 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 에서 기반된 것입니다. 그리고 여기서 인용되는 PPT 이미지 또한 모두 해당 강의에서 가져왔음을 알립니다. 추가적으로 여기에 작성된 코드들 또한 해당 강의의 github 에 올라와 있는 코드를 참고해서 만든 겁니다.



1. 구현 방향


  • 특정 IP 만 접근 가능하도록 Voter 추가
  • Voter 중에서 가장 먼저 심사하도록 함.
  • 허용된 IP 면 ACCESS_GRANTED 가 아닌 ACCESS_ABSTAIN 을 리턴해서 추가 심의 진행
  • 허용된 IP 가 아니면 ACCESS_DENIED 를 리턴하지 않고 즉시 예외를 발생하여 최종 자원 접근 거부





2. AccessIp 도메인 관련 클래스 생성


Entity class

import lombok.*;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Data
@Table(schema = "public", name = "ACCESS_IP")
@EqualsAndHashCode(of = "id")
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AccessIp implements Serializable {
	
	@Id
	@GeneratedValue
	@Column(name = "IP_ID")
	private Long id;
	
	@Column(name = "IP_ADDRESS", nullable = false)
	private String ipAddress;
}



Repository class

import io.security.corespringsecurity.domain.entity.AccessIp;
import org.springframework.data.jpa.repository.JpaRepository;

public interface AccessIpRepository extends JpaRepository<AccessIp, Long> {
	
	AccessIp findByIpAddress(String ipAddress);
}



DB INSERT

서버 한번 실행해서 자동 DDL 되도록한 후, 테이블에 직접 insert 해주자.

INSERT INTO public.access_ip
(ip_id, ip_address)
VALUES(0, '0:0:0:0:0:0:0:1');






3. Voter 생성


import io.security.corespringsecurity.security.service.SecurityResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

import java.util.Collection;
import java.util.List;

public class IpAddressVoter implements AccessDecisionVoter<Object> {
	
	@Autowired
	private SecurityResourceService securityResourceService;
	
	@Override
	public boolean supports(ConfigAttribute attribute) {
		return true;
	}
	
	@Override
	public boolean supports(Class<?> clazz) {
		return true;
	}
	
	@Override
	public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
		
		WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
		String remoteAddress = details.getRemoteAddress();
		
		List<String> accessIpList = securityResourceService.getAccessIpList();
		
		int result = ACCESS_DENIED;
		
		if (accessIpList.contains(remoteAddress)) {
			return ACCESS_ABSTAIN;
		}
		
		throw new AccessDeniedException("Invalid IP Address");
		
	}
	
}

이 Voter 를 이제 Spring Security 설정에 적용해주면 끝이다.



4. Spring Security 설정 적용

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    
    // 1. 빈 등록!
    @Bean
    public IpAddressVoter ipAddressVoter() {
        return new IpAddressVoter();
    }
    
    @Bean
    public AccessDecisionVoter<? extends Object> roleVoter() {
        RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy());
        return roleHierarchyVoter;
    }
    
    @Bean
    public RoleHierarchyImpl roleHierarchy() {
        return new RoleHierarchyImpl();
    }
    
    private List<AccessDecisionVoter<?>> getAccessDecistionVoters() {
        List<AccessDecisionVoter<? extends Object>> accessDecisionVoters = new ArrayList<>();
        
        // 2. 가장 먼저 IP가 심사가되도록 해야한다.
        accessDecisionVoters.add(ipAddressVoter());
        accessDecisionVoters.add(roleVoter());
        return accessDecisionVoters;
    }
    
    // AccessDecisionManager 에 최종 적용
    private AccessDecisionManager affirmativeBased() {
    
        AffirmativeBased affirmativeBased = new AffirmativeBased(getAccessDecistionVoters());
        return affirmativeBased;
    }
    
    
    // ... 생략 ...
}
profile
백엔드를 계속 배우고 있는 개발자입니다 😊
post-custom-banner

2개의 댓글

comment-user-thumbnail
2023년 8월 11일

안녕하세. 블로그 너무 잘봤습니다.. 평소에 스프링 시큐리티 공부하고싶었는데
이 블로그가 너무 큰 도움이 되었어요! 특히 class파일을 일일이 파헤쳐보며 로직을 검증하는게
너무 좋았어요 ㅎㅎ

시리즈 더 안나오나요?

1개의 답글