인프런 커뮤니티 질문&답변

전정환님의 프로필 이미지
전정환

작성한 질문수

스프링 시큐리티

SecurityContextHolder 관련해서

작성

·

1K

0

안녕하세요. 강의보면서 질문이 있어 문의 드립니다. (섹션 4. 실전프로젝트 - 인증 프로세스 Ajax 인증 구현)

------------------------------------------------------------------------------------------------------

SecurityConfig 구현은 http.csrf().disable(); 이렇게 설정하고 임의로

CustomUserDetails details = (CustomUserDetails) userDetailsService.loadUserByUsername("userId");

SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(details.getUserInfo(), null, details.getAuthorities()));

사용자 정보를 넣어 (디버깅으로 사용자 조회하여 데이터 들어가는것까지 확인했습니다. authorities 는 ROLE_USER)

------------------------------------------------------------------------------------------------------

사용하고자 하는 서비스에서 SecurityContextHolder.getContext().getAuthentication().getPrincipal()

호출하여 사용자 정보를 가져오려고 하는데 anonymous_user 라고 나오네요. SecurityConfig 에서 넣은 사용자 정보도 없고요.

강제로 인증되어 사용자 정보까지 가져오려면 어떻게 해야 할까요?

------------------------------------------------------------------------------------------------------

이렇게 하는 이유는 개발환경에서만 security를 풀어 SecurityContextHolder 를 사용하는 다른 곳에서 security 를 동작했을때와 같은 환경으로 사용하고자 합니다.

답변 1

0

정수원님의 프로필 이미지
정수원
지식공유자

제가 정확한 실행 환경을 모르겠으나 일단 먼저 이해하실 부분은 이렇습니다.

스프링 시큐리티의 SecurityContext 의 범위 즉 스코프는 ThreadLocal 입니다.

이 말 즉슨 서버에 접속해서 생성되는 각 스레드(사용자)는 저마다의 ThreadLocal 에 SecurityContext 를 가지고 있습니다.

만약 사용자가 인증에 성공했다면 SecurityContext 에는 UsernamePasswordAuthenticationToken 객체가 저장되어 있고 SecurityContext 는 ThreadLocal 에 저장되어 있으며 동시에 HttpSession 에도 저장되어 있습니다.

그리고 인증 이후에는 SecurityContextPersistenceFilter 가 인증 당시 HttpSession 에 저장되어 있던 SecurityContext 를 꺼내어서 SecurityContextHolder 에 담기 때문에 어플리케이션 전역적으로 참조가 가능하게 됩니다.

즉 SecurityContextHolder.getContext().getAuthentication() 로 인증객체를 얻을 수 있게 됩니다..

그런데 만약 지금 실행중인 스레드가 아닌 제 3의 스레드 혹은 실행 프로세스가 SecurityContextHolder.getContext() 를 실행하게 되면 스프링 시큐리티는 SecurityContextHolder.getContext() 를 호출한 제 3의 스레드에서 ThreadLocal 에 저장된 SecurityContext 를 찾게 되는데 해당 ThreadLocal 에는 인증 당시 저장한 SecurityContext 가 존재하지 않기 때문에 스프링 시큐리티는 SecurityContext 객체를 새롭게 생성해서 ThreadLocal 에 저장하게 되고 SecurityContextHolder 는 전략 모드에 따라 ThreadLocal 를 감싸게 됩니다.

그렇게 되면 제 3의 스레드는  Authentication 가 null 인 SecurityContext 의 상태로 스프링 시큐리티의 각 보안필터를 거치게 되는데 일반적으로 이럴 경우에는 AnonymousAuthenticationFilter 가  AnonymousAuthenticationToken 을 생성해서 principal 에는 anonymous_user 문자열 값을 저장하고 authorities 에는 ROLE_ANONYMOUS 권한을 저장해서 AnonymousAuthenticationToken 를 SecurityContext 객체에 담게 됩니다.

그래서 질의하신 내용이 여기에 해당되는지는 정확하게 모르겠으나 기억하실 점은 인증당시에 SecurityContext 에 저장한 Authentication 객체를 어떤 임의의 지점에서 다시 호출했을 때 저장된 Authentication 가 나오지 않는다면 동일한 스레드 내에서 호출한 것이 아닌 서로 다른 스레드에서 호출할 경우 그럴 수 있다는 점입니다.

다시 말씀드리면 SecurityContext 의 스코프는 ThreadLocal 이며 그렇기 때문에 각 스레드는 ThreadLocal 에 저장된 SecurityContext 를 공유하지 않는다는 점을 기억하시기 바랍니다.

혹시 소스를 올려주시면 좀 더 파악하기가 쉬울 것 같습니다.

전정환님의 프로필 이미지
전정환

작성한 질문수

질문하기