본 포스트는 제우스에서 세션 확인 및 유지를 위해 jSessionId를 사용할 때 주의사항에 대한 포스트입니다.

 

HTTP 프로토콜은 기본적으로 Stateless 합니다. 클라이언트에서 서버에 요청할 때마다 새로운 연결을 생성하고 응답을 받은 후에는 연결을 끊어 버리기 때문에 상태를 유지할 수가 없습니다.

 

jSessionId

그래서 대부분의 WAS Container에서는 jSessionId라는 값을 발급합니다. 브라우저나 혹은 앱의 HttpClient 등 클라이언트가 최초에 JEUS에 접근하면 Response Header에 jSessionId 값을 발급하여 응답합니다. 클라이언트는 이후 요청부터는 이 jSessionId를 Request Header의 Cookie에 넣어서 요청합니다.

 

이 값을 Key로 서버에서는 세션 영역을 사용하고 유지할 수 있고, Request Header에 jSessionId가 전달되었을 경우에는 새로운 jSessionId를 발급하지 않습니다.

 

중복 로그인 방지

보통 서비스에서 동시 로그인을 허용하지 않을 경우 [사용자 아이디 + jSessionId] 값으로 동일한 사용자가 여러 경로로 접속했는지를 판단합니다. 사용자가 로그인을 하면 테이블에 현재 로그인한 jSessionId 값을 저장하고 매 트랜잭션에서 현재 동일한 사용자 아이디로 다른 jSessionId에서 접속하고 있지 않은지 검사합니다.

 

아래와 같은 테이블을 사용합니다. (별도의 테이블을 사용할 수도 있고, 사용자 원장을 사용할 수도 있습니다.)

-- USER table
USER_ID VARCHAR(20),
SESSION_ID VARCHAR(100)

사용자가 로그인에 성공하면 SESSION_ID를 현재 Request 영역에 전달된 jSessionId로 Update 합니다.

UPDATE  USER
   SET  SESSION_ID = ${jSessionId}
 WHERE  USER_ID = ${userId}

애플리케이션에서 비교 로직은 테이블에서 해당 사용자의 SESSION_ID를 읽어 현재 Request 영역의 jSessionId와 비교합니다.

String sessionId = userVo.getSessionId();
String jSessionId = request.getSession().getId();

if (!jSessionId.equals(sessionId)) {
	throw new Exception(~~~);
}

 

이중화 환경일 경우

AP 인스턴스가 여러 대일 경우에도 세션 클러스터링 설정을 해두었으므로 세션을 잘 복제가 됩니다. 하지만 위 로직으로 중복 로그인 방지를 구현했을 경우 접속하는 인스턴스가 변경될 경우 로그인이 풀리는 현상이 발생했습니다.

부하 분산을 Sticky Round Robin 방식으로 하여, 사용자가 접속하는 인스턴스의 변경이 거의 발생하지는 않지만 그래도 인스턴스 별 reboot 등의 작업을 수행할 때 사용자들이 불편을 겪곤 했습니다.

 

JEUS의 경우 세션 클러스터링을 하면 동일한 jSession 아이디로 잘 복제가 되지만 아래와 같이 인스턴스 구분자가 postFix로 추가됩니다. 

17:31:33.406 jSession ID : aaaaaaaaaaaaaaaaaaaaa.xyz01 -> inst01 접속 시
17:31:33.406 jSession ID : aaaaaaaaaaaaaaaaaaaaa.vwy01 -> inst03 접속 시

하여 JEUS의 세션 클러스터링 환경에서 중복 로그인 방지 등을 구현할 때는 위의 로직이 아니라 postFix 앞 쪽만 비교하는 로직으로 변경이 필요합니다. 예를 들면 아래와 같습니다.

String sessionId = (userVo.getSessionId().indexOf(".") > -1) ? userVo.getSessionId().substring(0, userVo.getSessionId().indexOf(".")) : userVo.getSessionId();
String jSessionId = (request.getSession().getId().indexOf(".") > -1) ? request.getSession().getId().substring(0, request.getSession().getId().indexOf(".")) : request.getSession().getId();

if (!jSessionId.equals(sessionId)) {
	throw new Exception(~~~);
}
300x250

+ Recent posts