경주장

[스프링 시큐리티 주요 아키텍처 이해] Authentication 본문

스프링/스프링 시큐리티

[스프링 시큐리티 주요 아키텍처 이해] Authentication

달리는치타 2022. 2. 8. 14:27

스프링 시큐리티에서 인증 토큰(객체)으로 활용되는 것은 Authentication(인증)객체입니다.

package org.springframework.security.core;

import ...

public interface Authentication extends Principal, Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();	//권한 목록

    Object getCredentials(); //사용자 비밀번호

    Object getDetails(); //인증 부가정보

    Object getPrincipal(); // 사용자 아이디 or User객체

    boolean isAuthenticated(); //인증 여부

    void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

인터페이스이며 다양한 구현체를 가지고 있습니다.


SpringSeucurity가 제공하는 Authentication 구현체

@참고 intelij 구현체 찾기 단축키 ⌥⌘B(MacOS) 또는 Ctrl+Alt+B(Windows/Linux)

 

Authentication의 구현체는 Authentcation이 아닌 AuthenticationToken으로 네이밍하는 것이 컨벤션 인것 같습니다.

 

위의 8가지 구현체 중 AbstractAuthenticationToken을 제외한 모든 Token은 AbstractAuthenticationToken을 상속하여 구현되어있습니다.  AbstractAuthenticationToken은 Authentication 인터페이스의 추상메서드 중 getCredentials( ), getPrinciple( )을 제외하고는 모두 구현되어있습니다. 해당 메서드를 포함하여 수정, 추가 사항이 필요한 경우 AbstractAuthenticationToken을 상속하여 구현하면 Authentication의 구현체를 편리하게 만들 수 있습니다.


UsernamePasswordAuthenticationFilter 즉 Form 인증 방식에서 활용되는 인증 객체인 UsernamePasswordAuthenticationToken을 간단히 살펴보겠습니다.

//사용자 입력으로 생성된 인증객체
//권한정보가 비어있고, 인증 여부가 false이다.
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
    super((Collection)null);
    this.principal = principal;
    this.credentials = credentials;
    this.setAuthenticated(false);
}

//DB단 까지 찾아보고, 사용자 입력까지 검증하여 생성된 인증객체
//권한정보를 DB에서 찾아보았기 때문에 전달하고, 인증 여부가 true이다.
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
    super(authorities);
    this.principal = principal;
    this.credentials = credentials;
    super.setAuthenticated(true);
}

UsernamePasswordAuthenticationToken는 두가지 생성자를 제공합니다.

 UsernamePasswordAuthenticationFilter에서는 첫번째 생성자를 활용하여 사용자가 입력한 username, password로 principal (User 객체)를 통해 Token을 생성합니다. 이 Token 객체가 생성되어 ProviderManager -> AuthenticationProvider 까지 전달 됩니다.

 

AuthenticationProvider는 내부적으로 인증절차를 통해 인증에 성공한다면 UsernamePasswordAuthenticationToken의 두번째 생성자를 통해 인증된 Token을 생성합니다. Filter는 인증된 토큰을 전달 받아 세션/ SecurityContextHolder 등의 후속 작업을 하고 다음 필터를 호출합니다. 

 

자세한 Authentication Flow 다음 포스팅에서 다루겠습니다. 


생성자의 setAuthentication( )매서드 호출 부분을 살펴보면 첫번째 생성자는 this.setAuthenticated(false);를 두번째 생성자는 super.setAuthenticated(true)를 호출합니다. UsernamePasswordAuthenticationToken에 생성된  this.setAuthenticated( ) 매서드를 보면 

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);
    }

직접적으로 true를 호출하는 것을 Assert로 막아놓은 것을 확인 할 수 있습니다.