[Spring] 사용자 강제 로그아웃 시키기(HttpSession)

dondonee·2025년 3월 30일

사용자 강제 로그아웃 시키기

클라이언트로부터 특정 사용자를 강제 로그아웃 시킬 수 있냐는 문의를 받았다(그럴만한 이유가 있었다). 사용자의 세션을 추적하고 있지 않으므로 특정 사용자를 로그아웃 시키는 것은 불가능하다고 판단하여 일괄 로그아웃으로 진행하기로 했다.

이번 포스팅은 그 방법을 찾으면서 이것저것 알아본 것을 기록해보았다.



세션 기반 인증 방식

일단 사이트의 인증 방식은 세션 기반으로 되어 있다. 로그인 로직을 보면 다음과 같이 되어있으므로 세션 기반의 로그인인 것을 알 수 있다.

@RequestMapping(value="/uat/uia/actionLogin.do")
public String actionLogin(@ModelAttribute("loginVO") LoginVO loginVO, HttpServletRequest request, ModelMap model) throws Exception {
	...
	request.getSession().setAttribute("loginVO", loginVO);
    ...
}


세션이란

그러고보니 세션이란 정확히 뭘까?

HttpSession

Provides a way to identify a user across more than one page request or visit to a Web site and to store information about that user.
The servlet container uses this interface to create a session between an HTTP client and an HTTP server. The session persists for a specified time period, across more than one connection or page request from the user. A session usually corresponds to one user, who may visit a site many times. The server can maintain a session in many ways such as using cookies or rewriting URLs.

보통 로그인 세션이라고 하면 HttpSession을 지칭할 것이다.

웹은 무상태 프로토콜인 HTTP 기반으로 통신하기 때문에 어떤 정보를 지속적으로 유지할 수 없다. 따라서 JavaEE에서는 웹 애플리케이션에서 특정 정보를 유지하기 위한 HttpSession을 제공하며, 이를 통해 인증 기능을 구현할 수 있다.

일반적으로 세션 하나가 하나의 유저에 대응되고, 각 유저는 세션 ID(보통 JSESSIONID)로 구분된다. 세션 저장소는 키-값 맵 형태로 관리되는데, 요청에 따라 세션 ID에 맞는 사용자 정보 객체를 반환한다.

비연속적인 HTTP 요청에서 세션 ID를 유지하기 위해서는 쿠키를 사용할 수도 있고, 요청마다 세션 ID가 붙은 URL을 보내는 방식(URL Rewritng)을 사용할 수도 있다.


<session-config>
	<session-timeout>60</session-timeout>
	<tracking-mode>COOKIE</tracking-mode>
	<cookie-config>
		<http-only>true</http-only>
		<secure>true</secure>
	</cookie-config>
</session-config>

세션에 관한 설정은 WAS의 web.xml에서 할 수 있다.

  • <session-timeout>60</session-timeout> : 세션의 유효 기간이며, 분 단위이다.
  • <tracking-mode>COOKIE</tracking-mode> : URL 방식을 사용하지 않고 쿠키로만 세션을 유지하도록 한다.
  • <http-only>true</http-only> : 보안을 위해 브라우저에서 쿠키에 접근하는 것을 막고 HTTP 요청으로만 쿠키를 전송하도록 한다.
  • <secure>true</secure> : HTTPS 요청으로만 쿠키 전송을 허용하는 한 층 보안이 강화된 설정이다.


세션 저장소

그렇다면 세션을 삭제해야 하는데 세션은 어디에 저장되는 걸까?

찾아보니 Tomcat은 기본적으로 In-Memory 방식으로 세션을 저장한다고 한다. 즉 JVM heap 영역에 저장된다.

그런데 의문점은 클라이언트의 애플리케이션은 재기동을 해도 세션이 유지된다는 것이다. 왜 그런걸까? In-Memory 방식이 맞다면 재기동 시 이전의 정보가 사라져야 하는게 맞지 않을까?

그렇게 계속 서칭을 하다가 톰캣 context.xml에 다음 속성을 적용하고 재기동을 해 보니 세션이 초기화가 됐다.

<Manager pathname="" />

이 설정이 의미하는 것은 뭘까? 왜 이 설정을 해야만 세션이 초기화가 된 것일까?

먼저 <Manager>는 세션의 생성과 관리를 담당하는 Session Manager를 의미한다. 이 인터페이스의 기본 구현체는 StandardManager이다.

pathname 속성은 톰캣이 종료될 때 이전의 세션 상태를 저장하는 sessions.ser 파일의 경로를 지정한다. 이 파일이 존재한다면 재기동 시 세션 정보를 읽어와 이전의 세션 상태를 그대로 유지할 수 있다. 하지만 ""와 같이 빈 문자열을 지정하면 이 속성은 비활성화되어 sessions.ser 파일을 생성하지 않으므로 재기동 시 세션 정보가 초기화되는 것이다.

'혹시 sessions.ser을 삭제하면 재기동을 하지 않고도 일괄 로그아웃이 되지 않을까?' 하는 생각이 들었지만, sessions.ser은 톰캣이 종료될 때 생성되기 때문에 이것을 삭제한다고 해서 WAS의 메모리에서 관리되고 있는 세션이 삭제되는 것은 아니다.



외부 세션 저장소

특정 사용자의 세션을 삭제하고 싶거나 런타임 중에 세션을 삭제하고 싶다면 어떻게 해야 할까?

그러한 기능을 만들거나, 세션 저장소를 외부에 두면 된다. 외부 세션 저장소로 Oracle 등의 RDB를 사용할 수는 있지만 자주 조회되는 세션의 저장소로 사용하기에 I/O 속도가 너무 느리기 때문에 Redis와 같은 In-memory DB를 주로 사용한다고 한다.

외부에 세션 저장소를 두고 세션과 사용자를 매핑하여 추적한다면 외부에서 특정 사용자를 로그아웃 시키는것도 가능할 것이다.

또한 이러한 방식은 시스템 확장에도 유리하다. 현재 클라이언트의 사이트처럼 WAS 자체의 세션 저장소를 사용할 때는 여러 개의 WAS가 서로 세션을 공유할 수 없지만, 외부 저장소를 사용한다면 WAS가 여러 개여도 하나의 세션 저장소를 바라보게 하여 세션을 공유할 수 있기 때문이다.




🔗 References

0개의 댓글