SH.DevBlog 2024. 1. 2. 18:19

# AuthenticationProvider

  • 인증 논리를 담당하는 영역(요청을 허용할지, 거부할지를 여기서 담당한다.)
  • Spring Security에서 대표적으로 인증 논리를 정의하는 영역이다.

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

 

  • 현재 이 계약에서 알아야 할 메서드는 다음과 같다.
    • isAuthenticated() - 인증 프로세스가 끝났으면 true를 반환하고 아직 진행 중이면 false를 반환한다.
    • getCredentials() - 인증 프로세스에 이용된 암호나 비밀을 반환한다.
    • getAuthorities() - 인증된 요청에 허가된 권한의 컬렉션을 반환한다.

 

# SecurityContext 이용

  • Authentication 객체를 저장하는 인스턴스를 보안 컨텍스트라고 한다. (즉, 사용자의 정보를 저장한다.)
    • 스프링 시큐리티는 보안 컨텍스트 관리 전략으로 세 가지 전략을 제공한다.
      • MODE_THREADLOCAL : 각 스레드가 보안 컨텍스트에 독립적으로 저장
      • MODE_INHERITABLETHREADLOCAL : MODE_THREADLOCAL과 비슷하지만 비동기 메서드의 경우 보안 컨텍스트를 다음 스레드로 복사하도록 시큐리티에 지시한다.
      • MODE_GLOBAL : 모든 스레드가 같은 보안 컨텍스트 인스턴스를 보게 한다.
  • 사용방법은 아래의 소스코드와 같다.
@GetMapping("/hello")
    public String hello() {
        SecurityContext context = SecurityContextHolder.getContext() ;
        Authentication a = context.getAuthentication() ;

        System.out.println(a.getName());
        System.out.println(a.getCredentials());
        System.out.println(a.getDetails());
        System.out.println(a.getPrincipal());

        a.getAuthorities().stream().forEach(value -> {
            System.out.println(value.getAuthority());
        });

        return "Hello, " + a.getName() + "!" ;
    }
  • 결과값

  • 위 방식 보다는 아래 방식이 더 좋다.
@GetMapping("/hello")
public String hello(Authentication a) {
	return "Hello, " + a.getName() + "!" ;
}

 

# 비동기로 처리하는 경우

  • @Async를 활용하여 자식 스레드를 생성하는 경우는 ThreadLocal을 인식하지 못한다.
  • 이를 해결하기 위한 방안으로는 아래 코드와 같이 설정이 필요하다.
  • 다만, 이는 @Async를 사용했을 경우에만 적용된다. Thread를 코드상으로 직접 생성해서 사용하면 기존의 ThreadLocal 처럼 인식하지 못한다.
    @Bean
    public InitializingBean initializingBean() {
        return () -> SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL) ;
    }