Skip to content

Commit e7392bf

Browse files
authored
fix : 웹소켓 인증/인가 오류 수정 (#141)
1 parent c65af9d commit e7392bf

File tree

2 files changed

+29
-42
lines changed

2 files changed

+29
-42
lines changed

backend/src/main/java/com/back/domain/party/paryChat/controller/WebSocketController.java

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.back.domain.party.paryChat.dto.ChatMessageDto;
44
import com.back.domain.party.paryChat.entity.ChatMessage;
55
import com.back.domain.party.paryChat.service.ChatMessageService;
6+
import com.fasterxml.jackson.core.JsonProcessingException;
67
import com.fasterxml.jackson.databind.ObjectMapper;
78
import io.swagger.v3.oas.annotations.Operation;
89
import lombok.RequiredArgsConstructor;
@@ -16,8 +17,6 @@
1617
import org.springframework.messaging.handler.annotation.MessageMapping;
1718
import org.springframework.messaging.handler.annotation.Payload;
1819
import org.springframework.messaging.simp.SimpMessageSendingOperations;
19-
import org.springframework.security.core.annotation.AuthenticationPrincipal;
20-
import org.springframework.security.core.userdetails.User;
2120
import org.springframework.web.bind.annotation.*;
2221

2322
@RestController
@@ -34,53 +33,46 @@ public class WebSocketController {
3433

3534
private static final String CHAT_TOPIC = "chat-messages";
3635

37-
@MessageMapping("/chat.sendMessage") // 클라이언트가 메시지를 보내는 경로 (예: /app/chat.sendMessage)
38-
public void sendMessage(@Payload ChatMessageDto chatMessageDto, @AuthenticationPrincipal User user) {
39-
// 1. 메시지 발신자 설정
40-
chatMessageDto.setSenderEmail(user.getUsername());
36+
@MessageMapping("/chat.sendMessage")
37+
public void sendMessage(@Payload ChatMessageDto chatMessageDto) {
38+
// 인증을 사용하지 않으므로, 클라이언트가 DTO에 담아 보낸 senderEmail을 그대로 사용합니다.
39+
String senderEmail = chatMessageDto.getSenderEmail();
40+
log.info("Message received from sender: {}", senderEmail);
4141

42-
// 2. 메시지를 해당 파티의 채팅방으로 즉시 전송 (실시간성 확보)
43-
messagingTemplate.convertAndSend("/topic/party/" + chatMessageDto.getPartyId(), chatMessageDto);
44-
45-
// 3. 메시지 저장 작업을 Kafka로 오프로드 (비동기 및 안정성 확보)
42+
// 1. 메시지를 Kafka로 발행
4643
try {
47-
String messageJson = objectMapper.writeValueAsString(chatMessageDto);
48-
// 파티 ID를 키로 사용하여 같은 파티 메시지가 같은 파티션에 저장되도록 보장 (메시지 순서 보장)
49-
kafkaTemplate.send(CHAT_TOPIC, chatMessageDto.getPartyId().toString(), messageJson);
50-
} catch (Exception e) {
51-
// Kafka Producer 실패는 (일반적으로 일시적이지만) 심각하므로 ERROR 레벨로 기록합니다.
52-
log.error("Failed to send chat message to Kafka. Message: {}, Exception: {}", chatMessageDto, e.getMessage(), e);
53-
// Kafka 전송 실패는 데이터베이스에 기록을 남기지 못할 위험이 있지만,
54-
// 실시간 채팅 자체는 이미 클라이언트에 전달되었으므로 시스템을 중단하지 않고 로그만 남깁니다.
44+
String jsonMessage = objectMapper.writeValueAsString(chatMessageDto);
45+
kafkaTemplate.send("chat-messages", jsonMessage);
46+
} catch (JsonProcessingException e) {
47+
log.error("Failed to convert ChatMessageDto to JSON for Kafka: {}", e.getMessage());
5548
}
49+
50+
// 2. 메시지를 해당 파티의 채팅방으로 즉시 전송 (실시간성 확보)
51+
messagingTemplate.convertAndSend("/topic/party/" + chatMessageDto.getPartyId(), chatMessageDto);
5652
}
5753

5854
@MessageMapping("/chat.updateMessage")
59-
public void updateMessage(@Payload ChatMessageDto chatMessageDto, @AuthenticationPrincipal User user) {
60-
// 인증된 사용자의 이메일을 DTO에 설정
61-
chatMessageDto.setSenderEmail(user.getUsername());
55+
public void updateMessage(@Payload ChatMessageDto chatMessageDto) {
56+
57+
// DTO의 senderEmail을 사용하여 권한을 확인하고 메시지 수정
58+
ChatMessage updatedMessage = chatMessageService.updateMessage(chatMessageDto);
6259

63-
// 메시지를 업데이트하고 반환된 최신 정보를 브로드캐스트합니다.
64-
ChatMessage updatedMessage = chatMessageService.updateMessage(chatMessageDto); // DTO를 직접 넘기도록 수정
6560
ChatMessageDto updatedDto = new ChatMessageDto(updatedMessage);
6661
messagingTemplate.convertAndSend("/topic/party/" + updatedDto.getPartyId(), updatedDto);
6762
}
6863

6964
@MessageMapping("/chat.deleteMessage")
70-
public void deleteMessage(@Payload ChatMessageDto chatMessageDto, @AuthenticationPrincipal User user) {
71-
// 인증된 사용자의 이메일을 가져옵니다.
72-
String senderEmail = user.getUsername();
65+
public void deleteMessage(@Payload ChatMessageDto chatMessageDto) {
7366

74-
// 1. 서비스 메서드를 호출하여 메시지를 삭제합니다. 이 메서드는 이제 반환값이 없습니다.
67+
// DTO의 senderEmail을 사용하여 권한을 확인하고 메시지 삭제
68+
String senderEmail = chatMessageDto.getSenderEmail(); // DTO에서 Email을 가져와 사용
7569
chatMessageService.deleteMessage(chatMessageDto.getId(), senderEmail);
7670

77-
// 2. 클라이언트에 삭제 사실을 알리기 위한 DTO를 생성합니다.
7871
ChatMessageDto deletedDto = new ChatMessageDto();
7972
deletedDto.setId(chatMessageDto.getId());
8073
deletedDto.setPartyId(chatMessageDto.getPartyId());
81-
deletedDto.setContent(null); // 삭제되었음을 명확히 하기 위해 content를 null로 설정
74+
deletedDto.setContent(null);
8275

83-
// 3. 삭제된 메시지 정보를 브로드캐스트합니다.
8476
messagingTemplate.convertAndSend("/topic/party/" + deletedDto.getPartyId(), deletedDto);
8577
}
8678

backend/src/test/java/com/back/domain/party/partyChat/controller/WebSocketControllerTest.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,10 @@
2121
import org.springframework.http.MediaType;
2222
import org.springframework.kafka.core.KafkaTemplate;
2323
import org.springframework.messaging.simp.SimpMessageSendingOperations;
24-
import org.springframework.security.core.userdetails.User;
2524
import org.springframework.test.web.servlet.MockMvc;
2625
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
2726

2827
import java.util.Arrays;
29-
import java.util.Collections;
3028
import java.util.List;
3129

3230
import static org.mockito.ArgumentMatchers.any;
@@ -61,7 +59,6 @@ class WebSocketControllerTest {
6159
private ChatMessage chatMessage2;
6260
private Party party;
6361
private Member sender;
64-
private User user;
6562
private final Integer partyId = 1;
6663

6764
@BeforeEach
@@ -71,7 +68,6 @@ void setUp() {
7168
// Mock 객체 생성
7269
party = mock(Party.class);
7370
sender = mock(Member.class);
74-
user = new User("[email protected]", "password", Collections.emptyList());
7571

7672
// Mock 객체 동작 설정
7773
lenient().when(party.getId()).thenReturn(partyId);
@@ -103,17 +99,17 @@ void sendMessage_shouldSaveAndSendMessage() throws Exception {
10399
String messageJson = "{\"id\":null,\"senderEmail\":\"[email protected]\",\"content\":\"Hello, world!\",\"partyId\":1}";
104100
when(objectMapper.writeValueAsString(any(ChatMessageDto.class))).thenReturn(messageJson);
105101

106-
webSocketController.sendMessage(chatMessageDto, user);
102+
// 1. Controller 메서드 호출
103+
webSocketController.sendMessage(chatMessageDto);
107104

108-
// 1. 메시지 브로드캐스트 검증
105+
// 2. 메시지 브로드캐스트 검증
109106
verify(messagingTemplate, times(1)).convertAndSend(
110107
eq("/topic/party/" + partyId), eq(chatMessageDto)
111108
);
112109

113-
// 2. ChatMessageService.saveMessage 호출 대신 KafkaTemplate.send 호출 검증
110+
// 3. KafkaTemplate.send 호출 검증
114111
verify(kafkaTemplate, times(1)).send(
115112
eq("chat-messages"), // 토픽 이름
116-
eq(partyId.toString()), // 키 (파티 ID)
117113
eq(messageJson) // 메시지 내용
118114
);
119115
verify(chatMessageService, never()).saveMessage(any(ChatMessageDto.class)); // saveMessage가 호출되지 않았는지 확인
@@ -133,7 +129,7 @@ void updateMessage_shouldUpdateAndBroadcast() {
133129
.build();
134130
when(chatMessageService.updateMessage(any(ChatMessageDto.class))).thenReturn(updatedChatMessage);
135131

136-
webSocketController.updateMessage(chatMessageDto, user);
132+
webSocketController.updateMessage(chatMessageDto);
137133

138134
verify(chatMessageService, times(1)).updateMessage(
139135
eq(chatMessageDto)
@@ -153,12 +149,11 @@ void deleteMessage_shouldDeleteAndBroadcast() {
153149
ChatMessageDto deleteDto = new ChatMessageDto();
154150
deleteDto.setId(messageId);
155151
deleteDto.setPartyId(partyId);
156-
157-
User user = new User(senderEmail, "", Collections.emptyList());
152+
deleteDto.setSenderEmail(senderEmail);
158153

159154
doNothing().when(chatMessageService).deleteMessage(eq(deleteDto.getId()), eq(senderEmail));
160155

161-
webSocketController.deleteMessage(deleteDto, user);
156+
webSocketController.deleteMessage(deleteDto);
162157

163158
verify(chatMessageService, times(1)).deleteMessage(
164159
eq(deleteDto.getId()), eq(senderEmail)

0 commit comments

Comments
 (0)