[Spring Security] SecurityContext와 SecurityContextHolder란?

minseok Kim·2025년 3월 5일

Spring Security

목록 보기
15/15

Spring Security의 인증 과정에서는 해당 유저의 username, password, authorities 등의 정보를 담은 Authentication 객체가 생성된다.

AuthenticationManager가 성공적으로 인증 과정을 마치면, 해당 Authentication 객체를 SecurityContext라는 객체에 저장한다.

SecurityContextHolder는 이러한 SecurityContext를 관리하는 역할을 한다.
각 객체의 계층 구조는 아래와 그림과 같다.

Authentication에서 Principal에는 username, Credentials에는 password, Authroities에는 role과 같이 인증된 사용자의 정보가 담긴다.



SecurityContext

Authentication은 SecurityContext에 담긴다.
SecurityContext는 현재 thread가 실행되는 중에 필수적으로 필요한 security 정보를 담는 역할을 하는 인터페이스이다.

public interface SecurityContext {
	Authentiction getAuthentication();
    void setAuthentication(Authentication authentication);
}

SecurityContext는 위처럼 security를 위한 최소한의 역할인 Authentication에 대한 getter/setter 메서드만 가지고 있고, SecurityContextHolder가 SecurityContext를 관리한다.



SecurityContextHolder

SecurityContextHolder는 SecurityContext에 접근할 수 있게끔 도와주는 역할을 하는 helper class이다.
SecurityContextHolder가 SecurityContext를 저장하는 여러 전략들이 존재하는데, Spring에서는 기본적으로 ThreadLocal을 사용한다.
ThreadLocal 이외에도 다른 전략들이 존재하며 각 전략들은 각각 아래와 같은 방식으로 SecurityContext를 관리한다.

  • MODE_THREADLOCAL
    ThreadLocal 방식은 각 쓰레드 별로 security context를 갖게끔 하는 전략이다. 쓰레드가 다르다면 다른 쓰레드의 security context 정보를 사용할 수 없다.

  • MODE_INHERITABLETHREADLOCAL
    MODE_THREADLOCAL과 유사하나, 비동기 메서드로 새로운 쓰레드가 생성되었을 때 기존 security context의 정보를 새로운 쓰레드에게도 복사하여 전달한다.
    비동기 메서드는 @Async라는 어노테이션이 붙인 메서드이고, 해당 어노테이션이 붙은 메서드는 분리된 쓰레드에서 동작하는 역할을 한다.
    비록 쓰레드는 분리되지만, security context를 공유하게끔 하는 전략이다.

  • MODE_GLOBAL
    Global 전략은 모든 쓰레드가 같은 security context를 공유하는 전략으로, 실제 프로덕트에서는 잘 사용되지 않는다.

SecurityContextHolder가 어떤 전략을 취할 지 개발자가 명시적으로 정할 수 있는데, property 파일에서 spring.security.strategy로 모드를 지정할 수도 있고 아래와 같이 bean을 등록하는 코드를 작성해도 된다.

@Bean
public InitializatingBean initializingBean() {
	return () -> SecurityContextHolder.setStrategyName(
    			 SecurityContextHolder.MODE_GLOBAL);




코드에서 사용자 정보 불러오기

사용자 정보가 SecurityContextHolder에 저장된다는 것을 앞서 설명했는데, 컨트롤러와 같은 코드에서 사용자 정보를 불러오는 2가지 방법이 존재한다.

1) SecurityContextHolder에서 불러오기

@Controller
public class SomeController {
	@GetMapping(value = "/username")
    public String currentUserName() {
    	Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String currentPrincipalName = authentication.getName();
        return currentPrincipalName;
    }
}

SecurityContextHolder에서 SecurityContext를 부르고, SecurityContext에서 Authentication을 불러오는 방식이다.


2) Authentication을 메서드 인자로 선언

@Controller
public class SomeController {
	@GetMapping(value = "/username")
    public String currentUserName(Authentication authentication) {
    	return authentication.getName();
    }
}

기본적으로 Authentication을 함수의 인자로 주면 Spring이 자동으로 SecurityContextHolder로부터 Authentication을 추출한 값을 대입해준다.
Authentication이 아니라 Principal을 인자로 줘도 무방하다.

0개의 댓글