Spring Security 파헤치기

이민우·2024년 1월 4일
1

Spring Boot

목록 보기
17/20

Spring Security는 우리가 스프링 관련 프로젝트를 진행할 때, 로그인 기능을 구현하다 보면 자연스럽게 접할수 있다. 모두의 마당, 식구하자 프로젝트를 진행하면서 시큐리티를 다뤘지만, 구현에 집중하느라 Security 내부 동작에 대해선 이해가 부족한 채로 진행했다. 이번 기회를 통해 내부 동작 원리에 대해서 공부해보자 !

🔒 Spring Security란?

스프링 시큐리티 (Spring Security)는 스프링 기반 어플리케이션의 보안(인증과 권한, 인가)을 담당하는 스프링 하위 프레임워크.
보안과 관련해서 체계적으로 많은 옵션들을 제공해주기 때문에 개발자의 입장에서는 하나하나 보안 관련 로직을 작성하지 않아도 된다는 장점이 있다.

API에 권한 기능이 없으면, 아무나 회원 정보를 조회하고 수정하고 삭제할 수 있다. 따라서 이를 막기 위해 인증된 유저만 API를 사용할 수 있도록 해야하는데, 이때 사용할 수 있는 해결 책 중 하나가 Spring Security다.

1. Spring Security 용어

인증, 인가 개념에 대해서 집중적으로 이해해보자!

  • 인증(Authentication) : 해당 사용자가 본인인지 확인하는 절차
  • 인가(Authorization) : 인증된 사용자가 요청한 자원에 접근 가능한지결정하는 절차
  • 접근 주체(Principal) : 보호받는 Resource에 접근하는 대상
  • 비밀번호(Credential) : Resource에 접근하는 대상의 비밀번호
  • 권한 : 인증된 주체가 어플리케이션의 동작을 수행할 수 있도록 허락되어 있는지 결정
    • 인증 과정을 통해 주체가 증명된 이후 권한을 부여할 수 있다.
    • 권한 부여에 두 가지 영역이 존재하는데 웹 요청 권한과 메서드 호출 및 도메인 인스턴스에 대한 접근 권한 부여가 있다.

Spring Security는 기본적으로 인증 절차를 거친 후 인가 절차를 진행하게 되며, 인가 과정에서 해당 리소스에 대한 접근 권한이 있는지를 확인한다. 이러한 인증과 인가를 위해 Principal을 아이디로, Credential을 비밀번호로 사용하는 인증 방식을 사용한다.
spring security 에서는 기본적으로 세션 - 쿠키 방식을 사용하고 있다.

Spring Security 내부 동작 원리


스프링 시큐리티 구조의 처리 과정을 간단히 설명하면 다음과 같습니다다.

  • 1. 사용자가 로그인 정보와 함께 인증 요청을 한다.(Http Request)
  • 2. AuthenticationFilter가 요청을 가로채고, 가로챈 정보를 통해 UsernamePasswordAuthenticationToken의 인증용 객체를 생성한다.
  • 3. AuthenticationManager의 구현체인 ProviderManager에게 생성한 UsernamePasswordToken 객체를 전달한다.
  • 4. AuthenticationManager는 등록된 AuthenticationProvider(들)을 조회하여 인증을 요구한다.
  • 5. 실제 DB에서 사용자 인증정보를 가져오는 UserDetailsService에 사용자 정보를 넘겨준다.
  • 6. 넘겨받은 사용자 정보를 통해 DB에서 찾은 사용자 정보인 UserDetails 객체를 만든다.
  • 7. AuthenticationProvider(들)은 UserDetails를 넘겨받고 사용자 정보를 비교한다.
  • 8. 인증이 완료되면 권한 등의 사용자 정보를 담은 Authentication 객체를 반환한다.
  • 9. 다시 최초의 AuthenticationFilter에 Authentication 객체가 반환된다.
  • 10. Authenticaton 객체를 SecurityContext에 저장한다.
최종적으로 SecurityContextHolder는 세션 영역에 있는 SecurityContext에 Authentication 객체를 저장한다.사용자 정보를 저장한다는 것은 Spring Security가 전통적인 세션-쿠키 기반의 인증 방식을 사용한다는 것을 의미한다.

Spring Security 구조에 따른 주요 모듈


Authentication


현재 접근하는 주체의 정보와 권한을 담는 인터페이스이다. Authentication 객체는 SecurityContext에 저장되며,SecurityContextHolder를 통해 SecurityContext에 접근하고, SecurityContext를 통해 Authentication에 접근할 수 있다.
public interface Authentication extends Principal, Serializable {	
	// 현재 사용자의 권한 목록을 가져옴	
	Collection<? extends GrantedAuthority> getAuthorities();    	
	// credentials(주로 비밀번호)을 가져옴	
	Object getCredentials();    	
	
    Object getDetails(); 	
	// Principal 객체를 가져옴	
	Object getPrincipal(); 	
	// 인증 여부를 가져옴	
	boolean isAuthenticated();    	
	// 인증 여부를 설정함	
	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException; 
}

UsernamePasswordAuthenticationToken


UsernamePasswordAuthenticationToken은 Authentication을 implements한 AbstractAuthenticationToken의 하위 클래스로, User의 ID가 Principal 역할을 하고, Password가 Credential의 역할을 한다. UsernamePasswordAuthenticationToken의 첫 번째 생성자는 인증 전의 객체를 생성하고, 두번째는 인증이 완료된 객체를 생성한다.
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {

} public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken { 	\
		private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; 	
		// 주로 사용자의 ID에 해당	
		private final Object principal; 	
		// 주로 사용자의 PW에 해당	
		private Object credentials; 	
		// 인증 완료 전의 객체 생성	
		public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {		
		super(null);		
		this.principal = principal;		
		this.credentials = credentials;		
		setAuthenticated(false);	
	} 	
	// 인증 완료 후의 객체 생성	
	public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
				Collection<? extends GrantedAuthority> authorities) {		
				super(authorities);		
				this.principal = principal;		
				this.credentials = credentials;		
				super.setAuthenticated(true); 
				// must use super, as we override	
			}
		}

AuthenticationManager


인증에 대한 부분은 AuthenticationManager를 통해서 처리하게 되는데, 실질적으로는 AuthenticationManager에등록된 AuthenticationProvider에 의해 처리된다. 인증에 성공하면 두번째 생성자를 이용해 객체를 생성하여 SecurityContext에 저장한다.
public interface AuthenticationManager { 	
	Authentication authenticate(Authentication authentication) throws AuthenticationException; 
}

AuthenticationProvider


AuthenticationProvider에서는 실제 인증에 대한 부분을 처리하는데, 인증 전의 Authentication 객체를 받아서 인증이 완료된 객체를 반환하는 역할을 한다. 아래와 같은 인터페이스를 구현해 Custom한 AuthenticationProvider를 작성하고 AuthenticationManager에 등록하면 된다.
public interface AuthenticationProvider { 	
	Authentication authenticate(Authentication authentication) throws AuthenticationException; 	
	
	boolean supports(Class<?> authentication); 
}

ProviderManager


AuthenticationManager를 implements한 ProviderManager는 AuthenticationProvider를 구성하는 목록을 갖는다.
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {	
	public List<AuthenticationProvider> getProviders() {		
	return this.providers;	
	}
	
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {		
	Class<? extends Authentication> toTest = authentication.getClass();		
	AuthenticationException lastException = null;		
	AuthenticationException parentException = null;		
	Authentication result = null;		
	Authentication parentResult = null;		
	int currentPosition = 0;		
	int size = this.providers.size();
	// for문으로 모든 provider를 순회하여 처리하고 result가 나올때까지 반복한다.		
	for (AuthenticationProvider provider : getProviders()) { ... }	
	}
}

UserDetailsService


UserDetailsService는 UserDetails 객체를 반환하는 하나의 메소드만을 가지고 있는데, 일반적으로 이를 implements한 클래스에 UserRepository를 주입받아 DB와 연결하여 처리한다.
public interface UserDetailsService { 	

	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; 
	
}

SecurityContextHolder


SecurityContextHolder는 보안 주체의 세부 정보를 포함하여 응용프로그램의 현재 보안 컨텍스트에 대한 세부 정보가 저장된다.

SecurityContext


Authentication을 보관하는 역할을 하며, SecurityContext를 통해 Authentication을 저장하거나 꺼내올 수 있다.
SecurityContextHolder.getContext().setAuthentication(authentication);

SecurityContextHolder.getContext().getAuthentication(authentication);

profile
백엔드 공부중입니다!

0개의 댓글

관련 채용 정보