springframework/시작하자SpringSecurity

17.SecurityContextHolder, SecurityContext

Jungsoomin :) 2020. 9. 22. 13:14

SecurityContext

  1. Authentication보관소, 언제든 Authentication을 꺼내 사용할 수 있도록 제공되는 클래스이다.

  2. ThreadLocal 에 저장되어 아무 곳에서 참조가 가능하도록 설계됨

  3. ThreadLocal Thread 하나에 할당 된 저장소이다. 즉 Thread-Safe 하다.

  4. ThreadLocal은 인증 완료시 HttpSession 저장되어 Application 전반에서 참조가 가능하다.


SecurityContextHolder

 

SecurityContext를 감싸 저장하는 객체, 저장방법은 3가지이다.

 

  1. MODE_THREADLOCAL : 하나의 스레드 당 SecurityContext 를 할당 , default 값

  2. MODE_INHERITABLETHREADLOCAL : 부모 스레드와 자식 스레드에 관해 동일한 SecurityContext를 유지함, 즉 프로세스 안에서 쓰레드의 자식쓰레드에게도 SecurityContext 가 공유 됨

  3. MODE_GLOBAL : 응용 프로그램에서 단 하나의 SecurityContext를 저장


  • SecurityContextHolder.clearContext() : SecurityContext 정보를 초기화한다.

  • Authentication auth = SecurityContextHolder.getContext().getAuthentication()


동작 구조

  1. 사용자가 인증을 시도

  2. Server 에서 Request에 대한 고유의 Thread 가 만들어지고 Thread 에 대한 TreadLocal(전역저장소) 가 생성

  3. UsernamePasswordAuthenticationFilter 작동

  4. 실패시 SecurityContextHolder.clearContext()

  5. 성공시 UsernamePasswordAuthenticationFilter가  최종 Authentication 객체를 SecurityContextHolder에 담긴 ThreadLocal에 있는 SecurityContext에 담음 

  6. HttpSession"SPRING_SECURITY_CONTEXT"라는 이름으로 SecurityContext 를 저장


  • SecurityContextHolder > ThreadLocal > SecurityContext > Authentication 

ThreadLocal 생성전략 설정의 차이점

 

ThreadLocal 생성전략은 기술 된 3가지

  1. MODE_THREADLOCAL

  2. MODE_INHERITABLETHREADLOCAL

  3. MODE_GLOBAL

default 인 MODE_THREADLOCAL 의 경우에, 해당 컨트롤러의 Authentication 값은 null 이다.

@GetMapping(value = "/thread")
    public String thread(){

        new Thread(

                new Runnable() {
                    @Override
                    public void run() {
                        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                        //자식 쓰레드에서 확인해보자
                    }
                }

        ).start();

        return "thread";

    }

 


ThreadLocal 생성 전략 변경

 

SecurityContextHolder.setStrategyName(원하는 ThreadLocal 생성전략)

 

     여기서는 SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL) 이겠다.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest()
                .authenticated();

        http
                .formLogin();

        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);

    }
}

 

이렇게 설정하고 디버깅을 해보면 자식 스레드 에서도 SecurityContext 값이 공유되는 것을 볼 수 있다.