Spring Security

 

Spring 기반 애플리케이션 보안(인증, 권한, 인가 등)을 담당하는 Spring 하위 프레임워크

인증과 권한에 대한 부분을 Filter흐름에 따라 처리

 

Filter는 Dispatcher Servlet 으로 가기 전에 적용 >> 가장 먼저 URL 요청받음

Interceptor는 Dispatcher와 Controller 사이에 위치, 적용 시기가 다름

 

Spring Security는 보안 관련해서 많은 옵션 제공 >> 개발자 입장에서 보안 관련 로직 하나하나 작성하지 않아도 됨

 

 

 

 

Spring Security 아키텍쳐

 

 

동작 방식

 

1. Request 수신

사용자가 Form을 통해 로그인 정보가 담긴 Request 전송

 

2. Token 생성

Authentication Filter가 Request 수신

UserNamePasswordAuthenticationToken (인증용 객체) 생성

UserNamePasswordAuthenticationToken은 해당 요청을 처리할 수 있는 Provider 탐색에 사용

 

3. AuthenticationFilter로부터 인증용 객체 수신

AuthenticationManager에게 처리 위임

AuthenticationManager는 List형태로 Provider 보유

 

4. Token을 처리할 수 있는 Authentication Provider 선택

실제 인증을 할 AuthenticationProvider에게 인증용 객체 전달

 

5. 인증

인증 절차가 시작되면 Authencitation Provider 인터페이스 실행

DB에 있는 사용자 정보와 입력받은 로그인 정보 비교

 

6. UserDetailsService의 loadUserByUsername 메소드 수행

AuthenticationProvider 인터페이스에서 authenticate() 메소드 오버라이딩 

이 메소드의 파라미터로 인증용객체를 활용 >> 로그인 정보를 가져올 수 있음

 

7. DB 사용자 정보 가져오기 위해 UserDetailsService 인터페이스 사용

 

8. UserDetailsService 인터페이스는 입력된 로그인 username정보로 loadUserByUsername() 메소드 호출

DB에 있는 사용자 정보를 UserDetails 객체로 가져옴 (사용자 존재하지 않으면 예외 throw)

DB에서 가져온 사용자 정보와 로그인 정보 비교

일치 시 Authentication 참조 리턴, 일치하지 않으면 예외

 

9. 인증 완료

사용자 정보를 가진 Authentication 객체를 SecurityContextHolder에 저장

성공 시 AuthenticationSuccessHandler 실행

실패 시 AuthenticationFailurHandler 실행

 

 

 

인증(Authorization)과 인가(Authentication)

인증 (Authorization) : 해당 사용자가 본인이 맞는지 확인하는 절차

인가 (Authentication) : 인증된 사용자가 요청한 자원에 접근 가능한지 결정하는 절차

 

 

Spring Security는 기본적으로 인증 절차 거친 후 인가 절차 진행

인가 과정에서 해당 리소스에 대한 접근 권한이 있는지 확인

 

Spring Security에서는 인증, 인가를 위해 Principal을 아이디, Credential을 비밀번호로 사용하는 Crerdential 기반 인증방식 사용

 

Principal : 접근 주체, 보호받는 Resource에 접근하는 대상

Credential : 비밀번호, Resource에 접근하는 대상의 비밀번호

 

 

 

Spring Security 주요 모듈

 

SecurityContextHolder

보안 주체의 세부 정보를 포함

응용프로그램의 현재 보안 컨텍스트에 대한 세부 정보 저장

기본적으로

SecurityContextHolder.MODE_INHERITABLETHREADLOCAL 방법,

SecurityContextHolder.MODE_THREADLOCAL 방법 제공

 

 

SecurityContext

Authentication을 보관하는 역할

SecurityContext 통해 Authentication 객체 활용 가능

 

SecurityContextHolder.getContext().setAuthentication(authentication);
SecurityContextHolder.getContext().getAuthentication(authentication);

 

 

Authentication

현재 접근하는 주체의 정보와 권한을 담는 인터페이스

SecurityContext에 저장, SecurityContextHolder를 통해 SecurityContext에 접근

SecurityContext 통해 Authentication에 접근 가능

 

Public interface Authentication extends Principal, Serializable{
	// 현재 사용자의 권한 목록 가져옴
    Collection<? extends GrantedAuthority> getAuthroties();
    
    // credentials (비밀번호)를 가져옴
    Object getCredentials();
    
    Object getDetails();
    
    // Principal 객체 가져옴
    Object getPrincipal();
    
    // 인증 여부
    boolean isAuthenticated();
    
    // 인증 여부 설정
    void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

 

 

UsernamePasswordAuthenticationToken

Authentication을 Implements한 AbstractAuthenticationToken의 하위 클래스

User의 ID가 Principal 역할, Password가 Credential의 역할

첫 번째 생성자는 인증 전의 객체 생성, 두번째는 인증이 완료된 객체 생성

 

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;
    
    // 주로 사용자의 Password에 해당
    private Object credentials;
    
    // 인증 완료 전의 객체 생성
    public UsernamePasswordAuthenticationToken(Object principal, Ojbect credentials){
    
    	super(null);
        this.principal = principal;
        this.credentials = credentails;
        setAuthenticated(false);
	}
    
    // 인증 완료 후 객체 생성
    
    public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extendes GrantedAuthority> authrorities) {
    	
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
      	super.setAuthenticated(true); // super 로 사용해야 됨
	}
}

 

 

 

AuthenticationManager

인증에 대한 부분은 여기서 처리

실질적으로는 AuthenticationManager에 등록 된 AuthenticationProvider에 의해 처리

인증 성공하면 두번째 생성자를 이용해 객체 생성 >> SecurityContext에 저장

 

public interface AuthenticationManager {
	Authentication authentication(Authentication authenticationi) throws AuthenticationException;
}

 

AuthenticationProvider

실제 인증에 대한 부분 처리

인증 전의 Authentication 객체를 받아 인증이 완료된 객체를 리턴하는 역할

아래와 같은 인터페이스를 구현하여 커스텀한 AuthenticationProvider 작성하고 AuthenticationManager에 등록하면 됨

 

public interface AuthenticationProvider {

	Authentication authenticate(Authentication authentication) throws AuthenticationException;
    
    boolean supports(Class<?> authentication);
}

 

 

 

Provider

AuthenticationManager를 Implements한 ProviderManager는 AuthenticationProvider를 구성하는 목록 보유

 

public class ProviderManager implements AuthenticationManager, MessageSoureceAware, 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 : getProvider()){ ... }
	}
}

 

 

 

UserDetailsService

UserDetails 객체를 반환하는 하나의 메소드만 보유

일반적으로 이를 Implements한 클래스에 UserRepository를 주입받아 DB와 연결하여 처리

 

public interface UserDetailsService {

	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

 

 

 

UserDetails

인증에 성공하여 생성된 UserDetails 객체는 Authentication 객체를 구현한 UsernamePasswordAuthenticationToken을 생성하기 위해 사용

UserDetails를 Implements하여 처리 가능

 

public interface userDetails extends Serializable {

	// 권한 목록
    Collection<? extends GrantedAuthroty> getAuthorities();
    
    String getPassword();
    
    String getUsername();
    
    // 계정 만료 여부
    boolean isAccountNonExpired();
    
    // 계정 잠김 여부
    boolean isAccountNonLocked();
    
    // 비밀번호 만료 여부
    boolean isCredentialNonExpired();
    
    // 사용자 활성화 여부
    boolean isEnabled();
}

 

 

GrantedAuthority

현재 사용자(Principal)가 가지고 있는 권한을 의미

ROLE_ADMIN, ROLE_USER와 같이 ROLE_?? 형태로 사용

GrantedAuthority 객체는 UserDetailsService에 의해 불러올 수 있고, 특정 자원에 대한 권한이 있는지 검사하여 접근 허용 여부 결정

 

 

'끄적 > BE' 카테고리의 다른 글

Optional  (1) 2025.06.25
TCP UDP  (0) 2023.02.05
Servlet  (0) 2023.01.18
JPA vs MyBatis  (0) 2023.01.11
JPA N+1  (0) 2023.01.11

+ Recent posts