관리 메뉴

Rootable의 개발일기

Spring Security 구조 및 흐름 본문

Spring

Spring Security 구조 및 흐름

dev-rootable 2024. 1. 27. 09:51

스프링 시큐리티는 Authentication(인증)과 Authorization(인가)라는 두 가지 큰 흐름으로 처리된다.

 

때때로 Authorization을 'Access Control'이라고 말하기도 한다.

 

📌 인증 방식

 

  • 인증(Authentication) : Who are you?
  • 인가(Authorization) : What are you allowed to do?

 

스프링 시큐리티는 기본적으로 인증 절차를 거친 후 인가 절차를 진행하며, 인가 과정에서 해당 리소스에 접근 권한이 있는지 확인한다.

 

스프링 시큐리티에서는 인증과 인가를 위해 Principal을 아이디로, Credential을 패스워드로 로 사용하는 Crendential 기반의 인증 방식을 사용한다.

 

Principal(접근 주체) : 보호 받는 Resource에 접근하는 대상
Credential(비밀번호) : Resource에 접근하는 대상의 비밀번호

 

 

📌 Spring Security란

 


Spring 기반의 application 보안(인증과 권한, 인가 등)을 담당하는 스프링 하위 프레임워크

 

🔍 장점

 

  • 보안과 관련해서 많은 옵션을 제공해 주기 때문에 개발자 입장에서 일일이 보안 관련 로직을 작성하지 않아도 된다.
  • 자체적으로 세션을 체크하지 않아도 된다.
  • 로그인 완료 시 일일이 redirect하는 설정을 하지 않아도 된다.

 

🔍 특징

 

  • 스프링 시큐리티는 Filter 기반으로 동작하므로 Spring MVC와 분리되어 관리하고 동작할 수 있다.
  • Bean으로 설정할 수 있다.
    • Spring Security 3.2부터는 XML 설정을 하지 않아도 된다.

 

 

📌 Spring Security Architecture

 

 

1. 사용자가 로그인 정보와 함께 요청한 HTTP request를 수신하면 해당 요청은 인증 mechanism과 model을 기반으로 한 필터들을 통과한다.

 

  • HTTP 기본 인증 요청 : BasicAuthenticationFilter
  • HTTP Digest 인증 요청 : DigestAuthenticationFilter
  • Login Form에 의한 인증 요청 : UserPasswordAuthenticationFilter
  • 509 인증 요청 : X509AuthenticationFilter

 

2. UsernamePasswordAuthenticationToken의 AuthenticationToken(인증용 토큰) 생성

 

  • AuthenticationFilter는 요청 흐름을 가로채어 인증용 토큰을 생성한다.
  • 인증용 토큰은 해당 요청으로 받은 username과 password를 기반으로 생성되며 대부분의 인증 mechanism과 동일하다.

 

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {

    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
    
    private final Object principal; //User's ID

    private Object credentials; //Password
    
    //인증 전의 객체
    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
    }
    
    @Override
    public Object getCredentials() {
        return this.credentials;
    }

    @Override
    public Object getPrincipal() {
        return this.principal;
    }

    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        Assert.isTrue(!isAuthenticated,
            "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        super.setAuthenticated(false);
    }

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
        this.credentials = null;
    }

 

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

 

public interface AuthenticationManager {

  Authentication authenticate(Authentication authentication)
    throws AuthenticationException;
}

 

  • 가장 일반적인 구현은 AuthenticationManager가 자신을 구현한 ProviderManager에게 AuthenticationProvider Instances에게 인증 작업을 요구하도록 하는 것이다.
  • AuthenticationManager는 ProviderManager에게 AuthenticationToken을 전달
  • 인증에 성공하면 두 번째 생성자를 이용해 객체를 생성하여 SecurityContext에 저장한다.

 

4. ProviderManagerAuthenticationProvider Instances를 조회하여 인증을 요구한다.

 

  • 실제 인증에 대한 부분을 처리한다.
  • 인증 전의 Authentication 객체를 받아서 인증이 완료된 객체를 반환

 

public interface AuthenticationProvider {

    Authentication authenticate(Authentication authentication)
        throws AuthenticationException;

    boolean supports(Class<?> authentication);
}

 

5. 실제 DB에서 사용자 인증 정보를 가져오는 UserDetailsService에 사용자 정보를 넘겨준다.

 

  • UserDetailsService는 username을 기반으로 검색
  • 일반적으로 UserDetailsService를 implements 한 클래스에서 UserRepository를 주입받아 DB와 연결하여 처리한다.

 

public interface UserDetailsService {

  UserDetails loadUserByUsername(String username) 
      throws UsernameNotFoundException;
      
}

 

6. UserDetailsService는 넘겨받은 사용자 정보를 통해 DB에서 찾은 사용자 정보인 UserDetails 객체를 생성하여 리턴한다.

 

  • UserDetails는 UsernamePasswordAuthenticationToken을 생성하기 위해 사용됨
  • UserDetails를 implements 하여 처리할 수 있다.

 

public interface UserDetails extends Serializable {

    //권한 목록
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();
    
    String getUsername();
    
    //계정 만료 여부
    boolean isAccountNonExpired();
    
    //계정 잠김 여부
    boolean isAccountNonLocked();
    
    //비밀번호 만료 여부
    boolean isCredentialsNonExpired();

    //사용자 활성여부
    boolean isEnabled();

}

 

7. AuthenticationProvider Instances는 UserDetails를 넘겨받고 사용자 정보를 비교

 

8. 인증이 완료되면 권한 등의 사용자 정보를 담은 Authentication 객체를 리턴

 

  • Authenticaion은 현재 접근하는 주체의 정보와 권한을 담는 인터페이스다.
  • AuthenticationManager.authenticate(Authentication) method에 의해 인증 요청이 처리된 후 인증 요청 또는 인증된 주체에 대한 토큰을 나타낸다.
  • 일단 인증되면, Authentication은 보통 사용 중인 인증 mechanism에 의해 SecurityContextHolder에 의해 관리되는 SecurityContext에 저장된다.

 

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; 

}

 

GrantedAuthority

현재 사용자가 갖고 있는 권한을 의미하며, ROLE_*의 형태로 사용한다.

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

 

9. AuthenticationFilter에 Authentication 객체를 리턴

 

10. Authentication 객체를 SecurityContext에 저장

 

  • SecurityContextHolder는 세션 영역에 있는 SecurityContext에 Authentication 객체를 저장한다.
  • SecurityContext를 통해 Authentication을 저장하거나 꺼내올 수 있다.
  • 사용자 정보를 저장한다는 것은 스프링 시큐리티가 세션-쿠키 기반의 인증 방식을 사용한다는 것을 의미한다.

 

SecurityContextHolder

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

 

References:

 

https://dev-coco.tistory.com/174

 

Spring Security의 구조(Architecture) 및 처리 과정 알아보기

시작하기 앞서 스프링 시큐리티에서 어플리케이션 보안을 구성하는 두 가지 영역에 대해 간단히 알아보자. 인증(Authentication)과 인가(Authorization) 대부분의 시스템에서는 회원을 관리하고 있고,

dev-coco.tistory.com

 

https://twer.tistory.com/entry/Security-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0%EC%9D%98-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EA%B5%AC%EC%A1%B0-%EB%B0%8F-%ED%9D%90%EB%A6%84

 

[Security] 스프링 시큐리티의 아키텍처(구조) 및 흐름

Spring Security 스프링 시큐리티리란? 어플리케이션의 보안(인증 및 권한)을 담당하는 프레임워크 Spring Security를 사용하지 않으면 자체적으로 세션을 체크해야 한다. redirect를 일일이 설정해주어야

twer.tistory.com

 

https://spring.io/guides/topicals/spring-security-architecture/

 

Getting Started | Spring Security Architecture

This guide is a primer for Spring Security, offering insight into the design and basic building blocks of the framework. We cover only the very basics of application security. However, in doing so, we can clear up some of the confusion experienced by devel

spring.io

 

https://docs.spring.io/spring-security/site/docs/4.0.x/apidocs/org/springframework/security/core/Authentication.html

 

Authentication (Spring Security 4.0.4.RELEASE API)

Represents the token for an authentication request or for an authenticated principal once the request has been processed by the AuthenticationManager.authenticate(Authentication) method. Once the request has been authenticated, the Authentication will usua

docs.spring.io

 

'Spring' 카테고리의 다른 글

GenericFilterBean vs OncePerRequestFilter  (0) 2024.04.24
@Transactional  (0) 2023.08.08
스프링 파일 업로드/다운로드  (0) 2023.08.03
API 예외 처리  (0) 2023.08.01
예외 처리와 오류 페이지  (0) 2023.07.31