Skip to content

Commit 4d35ed5

Browse files
committed
Feat: WebSocketConfig에 세션 관리 연동 로직 추가
1 parent 4398a6d commit 4d35ed5

File tree

1 file changed

+106
-9
lines changed

1 file changed

+106
-9
lines changed

src/main/java/com/back/global/config/WebSocketConfig.java

Lines changed: 106 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.back.global.security.CustomUserDetails;
44
import com.back.global.security.JwtTokenProvider;
5+
import com.back.global.websocket.service.WebSocketSessionManager;
56
import lombok.RequiredArgsConstructor;
67
import lombok.extern.slf4j.Slf4j;
78
import org.springframework.context.annotation.Configuration;
@@ -28,6 +29,7 @@
2829
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
2930

3031
private final JwtTokenProvider jwtTokenProvider;
32+
private final WebSocketSessionManager sessionManager;
3133

3234
/**
3335
* 메시지 브로커 설정
@@ -55,11 +57,11 @@ public void registerStompEndpoints(StompEndpointRegistry registry) {
5557

5658
/**
5759
* WebSocket 메시지 채널 설정
58-
* JWT 인증 인터셉터 등록
60+
* JWT 인증 인터셉터 및 세션 관리 로직 등록
5961
*/
6062
@Override
6163
public void configureClientInboundChannel(ChannelRegistration registration) {
62-
// JWT 인증 인터셉터 등록
64+
// JWT 인증 + 세션 관리 인터셉터 등록
6365
registration.interceptors(new ChannelInterceptor() {
6466
@Override
6567
public Message<?> preSend(Message<?> message, MessageChannel channel) {
@@ -74,9 +76,19 @@ public Message<?> preSend(Message<?> message, MessageChannel channel) {
7476
authenticateUser(accessor);
7577
}
7678

77-
// SEND 시점에서도 인증 확인 (추가 보안)
79+
// SEND 시점에서 인증 확인 및 활동 시간 업데이트
7880
else if (StompCommand.SEND.equals(accessor.getCommand())) {
79-
validateAuthentication(accessor);
81+
validateAuthenticationAndUpdateActivity(accessor);
82+
}
83+
84+
// SUBSCRIBE 시점에서 방 입장 처리
85+
else if (StompCommand.SUBSCRIBE.equals(accessor.getCommand())) {
86+
handleRoomSubscription(accessor);
87+
}
88+
89+
// UNSUBSCRIBE 시점에서 방 퇴장 처리
90+
else if (StompCommand.UNSUBSCRIBE.equals(accessor.getCommand())) {
91+
handleRoomUnsubscription(accessor);
8092
}
8193
}
8294

@@ -111,24 +123,109 @@ private void authenticateUser(StompHeaderAccessor accessor) {
111123
// 세션에 사용자 정보 저장
112124
accessor.setUser(authentication);
113125

126+
log.info("WebSocket 인증 성공 - 사용자: {} (ID: {}), 세션: {}",
127+
userDetails.getUsername(), userDetails.getUserId(), accessor.getSessionId());
128+
114129
} catch (Exception e) {
130+
log.error("WebSocket 인증 실패: {}", e.getMessage());
115131
throw new RuntimeException("WebSocket 인증에 실패했습니다: " + e.getMessage());
116132
}
117133
}
118134

119135
/**
120-
* 메시지 전송 시 인증 상태 확인
136+
* 메시지 전송 시 인증 상태 확인 및 활동 시간 업데이트
121137
*/
122-
private void validateAuthentication(StompHeaderAccessor accessor) {
138+
private void validateAuthenticationAndUpdateActivity(StompHeaderAccessor accessor) {
123139
if (accessor.getUser() == null) {
124140
throw new RuntimeException("인증이 필요합니다");
125141
}
126142

127-
// 인증된 사용자 정보 로깅
143+
// 인증된 사용자 정보 추출 및 활동 시간 업데이트
128144
Authentication auth = (Authentication) accessor.getUser();
129145
if (auth.getPrincipal() instanceof CustomUserDetails userDetails) {
146+
Long userId = userDetails.getUserId();
147+
148+
// 사용자 활동 시간 업데이트
149+
sessionManager.updateLastActivity(userId);
150+
130151
log.debug("인증된 사용자 메시지 전송 - 사용자: {} (ID: {}), 목적지: {}",
131-
userDetails.getUsername(), userDetails.getUserId(), accessor.getDestination());
152+
userDetails.getUsername(), userId, accessor.getDestination());
153+
}
154+
}
155+
156+
/**
157+
* 방 채팅 구독 시 방 입장 처리
158+
*/
159+
private void handleRoomSubscription(StompHeaderAccessor accessor) {
160+
try {
161+
String destination = accessor.getDestination();
162+
163+
// 방 채팅 구독인지 확인: /topic/rooms/{roomId}/chat
164+
if (destination != null && destination.matches("/topic/rooms/\\d+/chat")) {
165+
Long roomId = extractRoomIdFromDestination(destination);
166+
167+
if (roomId != null && accessor.getUser() != null) {
168+
Authentication auth = (Authentication) accessor.getUser();
169+
if (auth.getPrincipal() instanceof CustomUserDetails userDetails) {
170+
Long userId = userDetails.getUserId();
171+
172+
// 방 입장 처리
173+
sessionManager.joinRoom(userId, roomId);
174+
175+
log.info("방 입장 처리 완료 - 사용자: {} (ID: {}), 방: {}",
176+
userDetails.getUsername(), userId, roomId);
177+
}
178+
}
179+
}
180+
} catch (Exception e) {
181+
log.error("방 구독 처리 중 오류 발생: {}", e.getMessage(), e);
182+
}
183+
}
184+
185+
/**
186+
* 방 채팅 구독 해제 시 방 퇴장 처리
187+
*/
188+
private void handleRoomUnsubscription(StompHeaderAccessor accessor) {
189+
try {
190+
String destination = accessor.getDestination();
191+
192+
// 방 채팅 구독 해제인지 확인: /topic/rooms/{roomId}/chat
193+
if (destination != null && destination.matches("/topic/rooms/\\d+/chat")) {
194+
Long roomId = extractRoomIdFromDestination(destination);
195+
196+
if (roomId != null && accessor.getUser() != null) {
197+
Authentication auth = (Authentication) accessor.getUser();
198+
if (auth.getPrincipal() instanceof CustomUserDetails userDetails) {
199+
Long userId = userDetails.getUserId();
200+
201+
// 방 퇴장 처리
202+
sessionManager.leaveRoom(userId, roomId);
203+
204+
log.info("방 퇴장 처리 완료 - 사용자: {} (ID: {}), 방: {}",
205+
userDetails.getUsername(), userId, roomId);
206+
}
207+
}
208+
}
209+
} catch (Exception e) {
210+
log.error("방 구독 해제 처리 중 오류 발생: {}", e.getMessage(), e);
211+
}
212+
}
213+
214+
/**
215+
* destination에서 방 ID 추출
216+
* ex) "/topic/rooms/123/chat" -> 123
217+
*/
218+
private Long extractRoomIdFromDestination(String destination) {
219+
try {
220+
if (destination == null) return null;
221+
222+
String[] parts = destination.split("/");
223+
if (parts.length >= 4 && "rooms".equals(parts[2])) {
224+
return Long.parseLong(parts[3]);
225+
}
226+
} catch (NumberFormatException e) {
227+
log.warn("방 ID 추출 실패 - destination: {}, 에러: {}", destination, e.getMessage());
132228
}
229+
return null;
133230
}
134-
}
231+
}

0 commit comments

Comments
 (0)