-
Notifications
You must be signed in to change notification settings - Fork 3
동일 토큰 중복 접속 제한
wlgh1553 edited this page Dec 3, 2024
·
3 revisions
- 동일한 토큰으로 여러 브라우저 탭이나 기기에서 접속할 경우 발생하는 문제를 해결하기 위해 중복 연결 제한 정책을 도입.
- 문제를 해결하는 과정에서 여러 접근 방식을 시도했으며, 최종적으로 중복 연결 제한을 통해 일관된 데이터 흐름을 확보.
-
Ask-It은 질문과 답변, 좋아요 액션이 전부 HTTP를 기반으로 하게되고 전송자는 응답으로 렌더링을 하지만 세션 참가인원들은 브로드캐스팅을 받아서 실시간 렌더링을 반영합니다. 그래서 소켓이 가지는 브로드캐스트 메소드를 이용해서 본인을 제외한 브로드캐스팅을 사용중이었습니다.
-
토큰과 소켓을 1:1로 매핑하다가 문제가 발생
this.socketToTokenMap.set(socket, { sessionId, token }); this.tokenToSocketMap.set(token, { sessionId, socket });
회원의 경우에는 세션별로 동일한 토큰을 찾아서 주게 설계가 되어있습니다. 이 과정에서 여러 탭이나 브라우저로 들어오게 된다면 tokenToSocketMap에서 기존의 소켓이 덮어써지기 때문에 다음과 같은 상황에서 문제가 발생하게 됩니다.
- case1) 기존 접속탭에서 질문이나 답변, 좋아요를 등록 → 토큰의 매핑된 소켓이 다른 장소의 소켓이기 때문에 신규접속 탭에서는 브로드캐스팅이 오지않습니다. 그리고 원래 접속한 곳에서는 브로드캐스팅과 HTTP 응답 둘 다 오기때문에 중복으로 렌더링이 이루어집니다.
- case2) 신규 접속탭에서 질문이나 답변, 좋아요를 등록 → 연결된 소켓이 브로드캐스팅을 하기때문에 정상적인 것처럼 보이지만, 저희는 HTTP 응답을 받아야 그 컴포넌트의 소유권을 가지고 수정과 삭제가 가능합니다. 그래서 기존의 동일 토큰으로 접속한 탭에서는 새로고침을 하지않으면 소유권을 가질 수 없습니다.
-
토큰에 배열을 매핑
private tokenToSocketMap = new Map<string, Socket[]>();
- 이 경우는 토큰에 매핑된 배열에서 HTTP 요청을 보낸 탭의 소켓을 식별해서 그 소켓을 제외하고 소유권을 지정해서 이벤트를 발생해야하는데 클라이언트가 소켓의 정보를 주지않으면 식별이 불가능해서 시도중에 선회했습니다.
-
동일 토큰 중복 제한
-
새 소켓 연결 시 기존 소켓을 강제로 연결 해제:
- tokenToSocketMap에는 항상 마지막 소켓만 유지.
- 덮어쓰기 문제를 제거하고 데이터 흐름을 단순화.
-
새 소켓 연결 시 기존 소켓을 강제로 연결 해제:
- 동일 토큰 중복 접속 제한
handleConnection(socket: Socket) {
const sessionId = socket.handshake.query.sessionId as string;
const token = socket.handshake.query.token as string;
const originalSocket = this.tokenToSocketMap.get(token);
if (!sessionId || !token) {
this.logger.warn(`Connection rejected: missing sessionId or token`, 'SocketGateway');
return socket.disconnect();
}
if (originalSocket) {
this.logger.warn(
`Duplicate connection detected: token=${token}, disconnecting previous connection`,
'SocketGateway',
);
originalSocket.socket.emit(SOCKET_EVENTS.DUPLICATED_CONNECTION);
originalSocket.socket.disconnect();
}
this.socketToTokenMap.set(socket, { sessionId, token });
this.tokenToSocketMap.set(token, { sessionId, socket });
socket.join(sessionId);
this.broadcastParticipantCount(sessionId);
this.logger.log(`Client connected: token=${token}, sessionId=${sessionId}, socketId=${socket.id}`, 'SocketGateway');
}
-
데이터 흐름 안정성 확보:
- 중복 연결로 인한 데이터 불일치 문제 해결.
- 브라우저 탭 간 데이터 일관성 유지.
-
서버 자원 효율성 향상:
- 배열 관리 대신 단일 소켓 매핑으로 자원 최적화.
-
복잡도 감소:
- 토큰-소켓 매핑 로직 단순화.
-
향후 개선점
-
다중 접속 지원 연구:
- 동일 토큰의 다중 접속을 지원할 수 있도록 소켓 그룹 관리 재검토.
-
브라우저 간 독립적 동작 지원:
- 동일 계정으로 여러 탭에서 독립적인 데이터 흐름을 처리할 방법 모색.
-
다중 접속 지원 연구: