Spring Security의 흐름과 개념 설명

2024. 8. 11. 16:52·Spring

Spring Security

  • 스프링 시큐리티는 인증(Authentication), 권한(Authorize) 부여 및 보호 기능을 제공하는 프레임워크이다.
  • 스프링 시큐리티는 짜여진 내부 로직을 통해 인증, 권한을 확인에 필요한 기능과 옵션들을 제공한다.

인증, 인가

  • 인증 : 해당 사용자가 본인이 맞는지를 확인하는 절차
  • 인가 : 인증된 사용자가 요청된 자원에 접근가능한가를 결정하는 절차.

인증 방식

  1. credential 방식 : username, password를 이용하는 방식
  2. 이중 인증(twofactor 인증) : 사용자가 입력한 개인 정보를 인증 후, 다른 인증 체계(예: 물리적인 카드)를 이용하여 두 가지의 조합으로 인증하는 방식이다.
  3. 하드웨어 인증 : 자동차 키와 같은 방식

→ Spring Security는 credential 방식 사용.

  • principal : 아이디(username)
  • credential : 비밀번호(password)

특정 자원에 대한 접근을 제어하기 위해서는 권한을 가지게 된다.

특정 권한을 얻기 위해서는 유저는 인증정보(Authentication)가 필요하고 관리자는 해당 정보를 참고해 권한을 인가(Authorization)한다.

보편적으로 username-password패턴의 인증방식을 거치기 때문에 스프링 시큐리티는 principa - credential 패턴을 거침.

특징

  • Filter를 기반으로 동작한다.
    • Spring MVC와 분리되어 관리하고 동작할 수 있다.
  • Bean으로 설정할 수 있따.

Spring Security의 흐름

1. HTTP Request 수신

→ 사용자가 로그인 정보와 함께 인증 요청을 한다.

2. 유저 자격을 기반으로 인증토큰 생성

→ AuthenticationFilter가 요청을 가로채고, 가로챈 정보를 통해

UsernamePasswordAuthenticationToken의 인증용 객체를 생성한다.

3. Filter를 통해 AuthenticationToken을 AuthenticationManager로 위임

→ AuthenticationManager의 구현체인 ProviderManager에게 생성한 UsernamePasswordToken객체를 전달한다.

4. AuthenticationProvider의 목록으로 인증을 시도

→ AutenticationManager는 등록된 AuthenticationProvider들을 조회하며 인증을 요구한다.

5. UserDetailsService의 요구

→ 실제 데이터베이스에서 사용자 인증정보를 가져오는 UserDetailsService에 사용자 정보를 넘겨준다.

6. UserDetails를 이용해 User객체에 대한 정보 탐색

→ 넘겨받은 사용자 정보를 통해 데이터베이스에서 찾아낸 사용자 정보인 UserDetails 객체를 만든다.

7. User객체의 정보들을 UserDetails가 UserDetailsService(LoginService)로 전달

→ AuthenticationProvider들은 UserDetails를 넘겨받고 사용자 정보를 비교한다.

8. 인증 객체 or AuthenticationException

→ 인증이 완료가 되면 권한 등의 사용자 정보를 담은 Authentication 객체를 반환한다.

9. 인증 끝

→ 다시 최초의 AuthenticationFilter에 Authentication 객체가 반환된다.

10. SecurityContext에 인증 객체를 설정

→ Authentication 객체를 Security Context에 저장

최종적으로는 SecurityContextHolder는 세션 영역에 있는 SecurityContext에 Authentication 객체를 저장한다. 사용자 정보를 저장한다는 것은 스프링 시큐리티가 전통적인 세션 - 쿠키 기반의 인증 방식을 사용한다는 것을 의미.

 

 

개념 설명

1) SecurityContextHolder, SecurityContext, Authentication

  • 인증에 성공하면 우리는 사용자의 Principal과 Credential정보를 Authentication 안에 담는다. 스프링 시큐리티에서 방금 담은 Authentication을 SecurityContext에 보관하고 이 SecurityContext를 SecurityContextHolder에 담아 보관하게 되는 것이다.

2) UsernamePasswordAuthenticationToken

  • Username(Principal)과 Password(credential)을 저장한다.
  • 첫 번째 생성자에는 인증 전에 객체를 생성하고
  • 두 번째 생성자에는 인증이 완료된 객체를 생성한다.
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
}
 
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
 
	private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
 
	private final Object principal;
 
	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
	}

3) AuthenticationManager

  • 인증에 대한 부분은 이 클래스를 통해서 처리가 된다.
  • AuthenticationManager에 등록된 AuthenticationProvider에 의해서 처리가 된다. 인증에 성공하면 두 번째 생성자를 이용해 생성한 객체를 SecurityContext에 저장한다.
public interface AuthenticationProvider {
 
	Authentication authenticate(Authentication authentication) throws AuthenticationException;
 
	boolean supports(Class<?> authentication);
 
}

4) AuthenticationProvider

  • 실제 인증에 대한 부분을 처리하는 작업을 치룸
  • 인증 전에 Authentication 객체를 받아 인증이 완료된 객체를 반환하는 역할을 하고 아래와 같이 인터페이스를 구현해 Custom한 AuthenticationProvider를 작성하고 AuthenticationManager에 등록하면 된다.

5) ProviderManager

  • AuthenticationManager를 구현한 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()) { ... }
	}
}

6) UserDetailsService

  • 이 클래스는 UserDetails 객체를 반환하는 하나의 메소드만을 가지고 있는데, 일반적으로 이를 구현한 클래스에서 UserRepostiory를 주입받아 DB와 연결하여 처리한다.
public interface UserDetailsService {
 
	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
 
}

7) UserDetails

  • 인증에 성공하여 생성된 UserDetails클래스는 Authentication 객체를 구현한 UsernamePasswordAuthenticationToken을 생성하기 위해 사용된다.
public interface UserDetails extends Serializable {
 
	Collection<? extends GrantedAuthority> getAuthorities();
 
	String getPassword();
 
	String getUsername();
 
	boolean isAccountNonExpired();
 
	boolean isAccountNonLocked();
 
	boolean isCredentialsNonExpired();
 
	boolean isEnabled();
 
}

8) GrantedAuthority

  • 현재 사용자(Principal)가 가지고 있는 권한을 의미하며 ROLE_ADMIN, ROLE_USER와 같이 ROLE_* 형태로 사용한다.
  • GrantedAuthority 객체는 UserDetailsService에 의해 불러올 수 있고, 특정 자원에 대한 권한이 있는지 없는지를 검사해 접근 허용 여부를 결정한다.

수행되는 Filter들

  • SecurityContextPersistenceFilter : SecurityContextRepository에서 SecurityContext를 가져오거나 저장하는 역할을 한다.
  • LogoutFilter : 설정된 로그아웃 URL로 오는 요청을 감시하며, 해당 유저를 로그아웃 처리
  • (UsernamePassword)AuthenticationFilter : (아이디와 비밀번호를 사용하는 form 기반 인증) 설정된 로그인 URL로 오는 요청을 감시하며, 유저 인증 처리
    • AuthenticationManager를 통한 인증 실행
    • 인증 성공 시, 얻은 Authentication 객체를 SecurityContext에 저장 후 AuthenticationSuccessHandler 실행
    • 인증 실패 시, AuthenticationFailureHandler 실행
  • DefaultLoginPageGeneratingFilter : 인증을 위한 로그인폼 URL을 감시한다.
  • BasicAuthenticationFilter : HTTP 기본 인증 헤더를 감시하여 처리한다.
  • RequestCacheAwareFilter : 로그인 성공 후, 원래 요청 정보를 재구성하기 위해 사용된다.
  • SecurityContextHolderAwareRequestFilter : HttpServletRequestWrapper를 상속한 SecurityContextHolderAwareRequestWapper 클래스로 HttpServletRequest 정보를 감싼다. SecurityContextHolderAwareRequestWrapper 클래스는 필터 체인상의 다음 필터들에게 부가정보를 제공한다.
  • AnonymousAuthenticationFilter : 이 필터가 호출되는 시점까지 사용자 정보가 인증되지 않았다면 인증토큰에 사용자가 익명 사용자로 나타난다.
  • SessionManagementFilter : 이 필터는 인증된 사용자와 관련된 모든 세션을 추적한다.
  • ExceptionTranslationFilter : 이 필터는 보호된 요청을 처리하는 중에 발생할 수 있는 예외를 위임하거나 전달하는 역할을 한다.
  • FilterSecurityInterceptor : 이 필터는 AccessDecisionManager 로 권한부여 처리를 위임함으로써 접근 제어 결정을 쉽게해준다.

'Spring' 카테고리의 다른 글

Gradle 개념 다지기  (0) 2025.04.16
DTO의 생성 위치(with 장점)  (3) 2025.01.19
Layered Architecture  (1) 2023.10.05
HTTP요청부터 응답까지의 과정  (0) 2023.09.25
IoC 컨테이너  (3) 2023.09.20
'Spring' 카테고리의 다른 글
  • Gradle 개념 다지기
  • DTO의 생성 위치(with 장점)
  • Layered Architecture
  • HTTP요청부터 응답까지의 과정
고선제
고선제
  • 고선제
    개발 로그
    고선제
  • 전체
    오늘
    어제
    • 분류 전체보기
      • JAVA
      • Spring
      • DB
      • 네트워크
      • JPA
      • Infra
      • Architecture
      • 여러가지
      • 우아한 테크코스
      • Test
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 관리
    • 글쓰기
  • 링크

  • 공지사항

    • 이 블로그의 시작을 알립니다.
  • 인기 글

  • 태그

    회고
    예약미션
    출석미션
    서비스역할
    enum
    http
    쿼리로 성능 개선
    aws mediconvert
    우테코
    개발자 마음가짐
    트랜잭션 전파 종류
    비상태성
    개발 태도
    쿠키와 세션 차이
    랜덤 테스트
    스프링 컨텍스트
    객체 그래프
    비연결성
    객체 설계
    우아한 테크코스
    테스트하기 쉬운코드
    restassured
    TEST
    test 작성범위
    우테고
    database layer
    성능
    트랜잭션 전파 순서
    application service
    @dirtycontext
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
고선제
Spring Security의 흐름과 개념 설명
상단으로

티스토리툴바