• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

안녕하세요 강사님 세션 관련 질문을 드립니다.

22.06.16 11:06 작성 조회수 229

0

안녕하세요 강사님 지금 QA진행중인 시스템이 있습니다.
 
스프링시큐리티를 기반으로 만들었고,
계층권한, ipvoter등을 적용 했습니다.
 
개발환경 및 dev 까지는 서버가 한대라서 이슈가 없었는데
 
stage 서버 두대인 곳에서 운영을 시작하다보니 이슈가 생겼습니다.
 
하지만 이 이슈는 ip hash를 통해서 로드벨런싱을 시켜서 어느정도 해소가 되는 분위기 였습니다.
 
 
그런데 또 발 생한 이슈는
 
ip hash가 되지만
 
동일한 계정으로 로그인을 여러 PC에서 시도를 하고
한 쪽 피씨에서 로그아웃을 하면서 context를 clear처리를 하게 되면
 
다른 PC에서 세션이 활성화 되어있는 사용자에게도 영향이 가고 있습니다.
 
지금 현재 처리로직은 custom 한 filter에서 request가 들어오면
쿠키를 검사하여 context를 생성하고
다른 pc에서 로그아웃을 할 것을 대비해
interceptor에서 한번 더 체크하여 쿠키 리프레쉬 및 context를 재생성 합니다.
 
하지만 controller -> service 쪽 까지 진입을 하는 과정에서 동일 하게 오류가 재현이 되고 있습니다.
 
그래서 로그아웃을 하면 context도 함꼐 사라지는 듯한 의심이 들고 있습니다. ( 제 생각 입니다..)
 
시큐리티 context는 ThreadLocal로 .. ThreadSafe인 것 으로 알고 있는데...
 
서두가 너무 길었죠.. 질문입니다.
 
1. 같은 계정으로 로그인을 한다면 하나의 context가 생성 되고 그것을 공유하는 것 인 걸까요?..
 
2. 아니면 ThreadSafe인데 제가 어딘가 의도치 않게 동기화가 되게끔 처리를 했을까요.?
 
3, 만약 같은 계정 로그인시 동일한 context가 생성이 된다면 ip같은 것으로 다른 context인것 처럼 생성 하고 싶은데 방법이 있을까요??
 
감사합니다.
 
ps.
바로 일전 프로젝트도 스프링시큐리티로 구현을 했지만
권한, 및 voter의 기능을 쓰지 않고 쿠키 및 일반 적인 처리를 해서 이슈가 없었습니다.
 

답변 2

·

답변을 작성해보세요.

0

sonbbang님의 프로필

sonbbang

질문자

22.06.20 18:21

안녕하세요 강사님 답변 정말 감사합니다.

추가 문의 좀 하겠습니다..

 
혹시 제 Logout처리 부분에서 잘 못 처리 된게 있을지 좀 알려주실 수 있으십니까?
 
config 쪽 로그아웃 관련 설정입니다.
@Override
protected void configure(HttpSecurity http) throws Exception {
.logout()
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/api/v1/logout"))
.logoutSuccessHandler(new LogoutHandler(homeService))

로그아웃 헨들러

@Slf4j
@RequiredArgsConstructor
public class LogoutHandler extends SimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler {

private final HomeService homeService;

@Override
@Transactional
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {

LoginCode logout = homeService.logout(request, response);
log.info("logout result : {}", logout.getDescription());

ResponseCookie refreshToken = homeService.removeCookie(request);
response.setHeader("Set-Cookie", refreshToken.toString());

this.setDefaultTargetUrl("/login");
super.onLogoutSuccess(request, response, authentication);
}
}

 

이번에 QA를 진행해보아도

한 PC에서 로그인을 한 상태에서, 다른 QA분들 (약10분 정도) 가 로그인/로그아웃을 반복 수행했습니다.

동일하게 RoleVoter나, IpVoter쪽에서 context 검사 후 AuthenticationEntryPoint 이쪽에 걸렸습니다.

 

removeCookie 쪽에는 단순히 쿠키의 age를 0으로 재생성해주는 쿠키 제거 function 입니다.

로그아웃 과정에서 어떤 문제가 있길래 모든 context가 처리 되는지 알고 싶습니다..

감사합니다...!

 

질문 update

clearAuthentication

이부분이 혹시 전체 authentication을 삭제가 가능한가 싶어서 내부를 타고 들어가도

현재 인증 정보를 제거한다라는 로직 같기만 하고 제가 우려한 부분은 아니더라구요.

ip hash등의 임시 방편으로 이것이 해결이 되는 건가 싶었는데.

금일 라이브QA에서도 동일한 현상이 발생 했습니다.

 

강사님의 질문에 대해서 제가 정리를 해보면

request가 들어오면 filter에서 제가 생성한 context 로 rolevoter 등이 체크를 하고 response 할 때 context가 없어지는 것 같은데... 일반적인 java RequestContext 같은 것과 같은 의미로 전 이해했습니다.

 

그럼 logout쪽에 clearAuthentication 이나 logoutHandler쪽에 SecurityContextHoler.getContext().setAuthentication(null);

이런 적업을 안해줘도 되는 걸까요??

어차피 하나의 request 안에서만 생성 되고 없어지는 context 이니깐요.

 

감사합니다.

수강생 올림.

 

https://www.inflearn.com/questions/53657 이거랑 비슷한 이슈인 것 같기도 하구요..

0

정수원님의 프로필

정수원

지식공유자

22.06.20 01:21

1. 같은 계정으로 로그인을 한다면 하나의 context가 생성 되고 그것을 공유하는 것 인 걸까요?..
 
context 는 메모리 기반이기 때문에 서버간에는 당연히 공유가 되지 않습니다.
redis 와 같은 세션 공유 서버를 사용할 경우에는 공유할 수 있겠지만 그렇지 않으면 동일한 계정으로 로그인한다고 해서 context 가 공유되지는 않습니다.
그리고 같은 서버내에서 동일한 계정으로 여러군데에서 인증접속이 이루어졌다고 해도 반드시 context 가 공유되지는 않습니다.
securityContext 는 세션 기반이 아닌 ThreadLocal 기반으로 요청당 생성되기 때문에 요청이 이루어지고 응답하게 되는 시점에는 다시 clear 됩니다.
그래서 securityContext 가 동일한 계정으로 여러명이 인증을 받았다고 해도 같은 securityContext 을 공유하지는 않습니다.
다만 전제 조건이 있다면 securityContext 가 최종적으로는 세션에 저장되기 때문에 만약 동일계정의 여러명이 동일한 세션을 공유하고 있다면 securityContext 를 공유할 수 는 있지만 정상적인 상황에서는 발생할 수 없는 경우라 볼 수 있습니다.
 
 
2. 아니면 ThreadSafe인데 제가 어딘가 의도치 않게 동기화가 되게끔 처리를 했을까요.?
 
음 ThreadLocal 자체가 동시성 문제에서 자유롭기 때문에 임의적으로 동기화할 수 있을지 의문입니다.
ThreadLocal 이 스레드 마다 별도로 할당되는 저장소 개념이기 때문에 스레드간 데이터를 공유하는 로직을 아주 어렵게 구현하지 않는 이상 별로 가능성이 없어 보입니다.
 
3, 만약 같은 계정 로그인시 동일한 context가 생성이 된다면 ip같은 것으로 다른 context인것 처럼 생성 하고 싶은데 방법이 있을까요??
 
같은 계정 로그인시 동일한 context 가 생성이 된다면의 전제조건은 같은계정을 로그인하는 사용자들의 세션쿠키가 다 동일해야 함을 의미합니다.
위에서 말씀드렸지만 그래야 동일한 세션에 저장된 context 를 공유할 수 있습니다.
securitycontext 는 특별한 클래스가 아닙니다. 그저 Authenticatoin 을 저장하기 위한 객체에 불과합니다.
다만 SecurityContextHolder 가 securityContext 를 Map 이 아닌 ThreadLocal 를 사용하여 저장한다는 개념이 동시성 문제를 해결하기 위한 좋은 전략인 정도라 보시면 됩니다.
 
일단 이론적으로는 설명드렸지만 실제적으로 테스트하신 환경에서 확인해 봐야 저도 정확한 분석이나 원인을 파악할 수 있을 것 같습니다.
 
그리고 SecurityContext 와 ThreadLocal 그리고 Session 과의 상관관계를 정확하게 파악하시는 것을 중요합니다.