Spring | Spring Security + JWT(1)

초보개발자 시점·2024년 2월 4일

Spring

목록 보기
2/2
post-thumbnail

인증/인가

  • 스프링 시큐리티 구현에 앞서, 어떠한 기능을 하는지, 그리고 어떠한 역할을 맡고 있는지, 무엇을 제공하는지 알아보겠습니다.

인증(Authentication)

  • 인증이란, 식별 가능한 정보를 통해서 서비스의 등록 유저라는 것을 증명하는 것입니다.
  • 예를 들어, 서비스에 가입된 사용자에게만, 서비스를 제공하는 것입니다.
    - 은행에 업무를 보고 싶다면, 창구에서 은행직원에게 우리는 신분증을 통해 인증할 수 있습니다.
    - 비행기를 타고 싶다면, 공항에서 여권을 통해 우리는 인증할 수 있습니다.

인가(Authorization)

  • 인가란, 사용자가 요청을 실행할 수 있는 권한이 있는가를 확인하는 절차입니다.
  • 예를 들어, 놀이공원에서 놀이기구를 탈 때, 직원은 우리의 이름이나, 신분에는 관심이 없습니다. 놀이기구를 탈 수 있는지 여부에만 관심이 있어 우리는 신분증이 아닌, 놀이공원 티켓만 있으면 됩니다.

요약하자면, 인증은 우리의 신원을 증명하는 행위이고, 인가는 접근권한을 부여하거나 거부하는 행위입니다.


Spring Security

  • Spring Security는 Spring 기반의 웹 애플리케이션의 인증(Authentication)및 권한 부여(Authorization)를 담당합니다. Security는 다양한 보안 기능을 제공하여 애플리케이션의 안정성을 강화합니다.

Architecture

  • Http Request(요청)이 서버로 전송됩니다.

  • AuthenticationFilter가 요청을 받습니다.

  • AuthenticationFilter에서 Request의 Id,Password를 이용하여 AuthenticationToken을 생성합니다.

  • 토큰을 AuthenticationManager가 받습니다.

  • AuthenticationManager는 토큰을 AuthenticationProvider에게 토큰을 넘겨줍니다.

  • AuthenticationProvider는 UserDetailsService로 토큰 사용자의 Id를 전달하여, 데이터베이스에서 Id존재를 확인합니다.

  • UserDetailsService는 데이터베이스의 회원정보를 UserDetails라는 객체로 반환 받습니다.

  • AuthenticationProvider는 반환받은 UserDetails 객체와 실제 사용자의 입력정보를 비교합니다.

  • 비교가 완료되면 사용자 정보가 담긴 Authentication 객체를, 다시 SecurityContextHolder에 담은 이후 AuthenticationSuccessHandle을 실행합니다.

    • 만약 실패시 AuthenticationFailureHandler를 실행합니다.

역할

Authentication

  • 요청을 보낸 사용자(주체)의 정보와 권한을 담는 인터페이스입니다. Authentication 객체는 SecurityContext에 저장되고, SecurityContextHolder를 통해 SecurityContext에 접근하여, Authentication에 접근할 수 있습니다.
public interface Authentication extends Principal, Serializable {
	
	Collection<? extends GrantedAuthority> getAuthorities();
    
	Object getCredentials();
    
	Object getDetails();
    
	Object getPrincipal();
    
	boolean isAuthenticated();
    
	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
  • Collection<? extends GrantedAuthority> getAuthorities();
    • 사용자의 권한 목록을 가져옵니다.
  • Object getCredentials();
    • 현재 사용자의 인증 정보(자격 증명)를 반환합니다. 주로 비밀번호를 가져옵니다.
  • Object getDetails();
    • 현재 인증된 사용자와 관련된 추가적인 세부 정보를 반환합니다.
  • Object getPrincipal();
    • 현재 인증된 사용자의 주체(principal)를 반환합니다. 주로 Id또는 사용자 객체가 될 수도 있습니다.
  • boolean isAuthenticated();
    • 현재 사용자가 인증되었는지 여부를 나타내는 값을 반환합니다.
    • 만약 사용자가 아직 인증되지 않았다면 (false 반환), 해당 사용자는 로그인되어 있지 않거나, 로그인이 실패했거나, 아직 인증이 완료되지 않은 상태일 수 있습니다.
  • void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
    • Authentication 객체의 인증 상태를 설정할 때 사용됩니다.

UsernamePasswordAuthenticationToken

  • UsernamePasswordAuthenticationToken 첫 번째 생성자는 인증 전의 객체를 생성하고, 두 번째 생성자는 인증이 완료된 객체를 생성한다.
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); 
	}

 }
  • private final Object principal;
    • principal 필드는 사용자의 주체를 나타냅니다. 주로 사용자 이름, ID를 나타냅니다.
  • private Object credentials;
    • credentials 필드는 사용자의 자격 증명을 나타냅니다. 일반적으로 사용자가 입력한 비밀번호가 여기에 저장됩니다.
  • public UsernamePasswordAuthenticationToken(Object principal, Object credentials){...}
    • 첫 번째 생성자는 인증 전, 즉 인증되지 않은 객체를 생성합니다. setAuthenticated(false) 인증되지 않은 상태로 설정되어 있습니다.
  • public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {...}
    • 두 번째 생성자는 인증 후, 즉 인증된 객체를 생성합니다. super.setAuthenticated(true); 토큰이 인증된 상태로 설정합니다.

AuthenticationManager

public interface AuthenticationManager {

	Authentication authenticate(Authentication authentication) throws AuthenticationException;
    
}
  • Authentication authenticate(Authentication authentication) throws AuthenticationException;
    • 인증을 수행하는 핵심 메서드 중 하나이며, Authentication 객체를 사용하여 사용자를 인증하고, 성공적으로 인증된 경우 인증된 Authentication 객체를 반환합니다.

AuthenticationProvider

public interface AuthenticationProvider {

	Authentication authenticate(Authentication authentication) throws AuthenticationException;
    
    boolean supports(Class<?> authentication);
    
}
  • Authentication authenticate(Authentication authentication) throws AuthenticationException;
    • 이 메서드는 사용자의 인증을 시도하고, 인증에 성공하면 Authentication 객체를 반환합니다.
  • boolean supports(Class<?> authentication);
    • 보통 여러 종류의 Authentication 객체가 존재하며, supports 메서드는 특정 구현이 해당 AuthenticationProvider에 의해 처리될 수 있는지 확인합니다.

AuthenticationManager VS AuthenticationProvider

  • 두개의 인터페이스를 보면 동일한 메서드가 존재하는 데, AuthenticationProvider는 실제로 인증을 수행하는 데 사용됩니다. AuthenticationManager는 AuthenticationProvider를 관리하고 호출하여 프로세스를 조율하는 역할을 합니다.

Provider

public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {

	@Override
	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 (AuthenticationProvider provider : getProviders()) {...}
    
}
  • AuthenticationManager를 implements한 ProviderManager는 AuthenticationProvider를 구성하는 목록을 갖는다.

UserDetailsService

public interface UserDetailsService {

	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
    
}
  • UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
    • 보통 이 인터페이스를 구현하여, 사용자 데이터베이스에서 사용자 정보를 가져오는 로직을 구현합니다.

UserDetails

  • UserDetails 인터페이스를 구현하는 클래스는 사용자의 상세 정보를 제공하는데 사용됩니다. 일반적으로 사용자 객체를 나타내는 클래스가 이 인터페이스를 구현합니다.

public interface UserDetails extends Serializable {

	Collection<? extends GrantedAuthority> getAuthorities();

	String getPassword();
    
	String getUsername();

	boolean isAccountNonExpired();

	boolean isAccountNonLocked();
    
	boolean isCredentialsNonExpired();
    
	boolean isEnabled();

}
  • Collection<? extends GrantedAuthority> getAuthorities();
    • 사용자가 가지고 있는 권한을 나타내는 GrantedAuthority 객체들의 컬렉션을 반환합니다.
    • GrantedAuthority는 사용자에게 부여된 특정 역할이나 권한을 나타내는 인터페이스입니다.
  • String getPassword();
    • 사용자의 비밀번호를 반환합니다.
  • String getUsername();
    • 사용자의 이름을 반환합니다. 일반적으로는 고유한 식별자로 반환할 수도 있습니다.
  • boolean isAccountNonExpired();
    • 사용자 계정의 유효 기간이 만료되었는지 여부를 나타내는 값을 반환합니다.
  • boolean isAccountNonLocked();
    • 사용자 계정이 잠겨 있는지 여부를 나타내는 값을 반환합니다.
  • isCredentialsNonExpired();
    • 사용자 자격증명(비밀번호)의 유효 기간이 만료되었는지 여부를 나타내는 값을 반환합니다.
  • isEnabled();
    • 사용자 계정이 활성화되어 있는지 여부를 나타내는 값을 반환합니다.

SecurityContext

  • Authentication을 저장하고 관리하는 객체이며, SecurityContextHolder를 통해 접근(엑세스)할 수 있습니다.
SecurityContextHolder.getContext().setAuthentication(authentication);
SecurityContextHolder.getContext().getAuthentication(authentication);

마무리하면서

  • Spring Security의 동작 방식과 각각의 역할을 알아보았습니다. 다음 글에서는 코드로 적용해 보도록 하겠습니다.
profile
뭘 모르는지를 모르겠는

0개의 댓글