Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,48 @@
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.util.Objects;

@Component
@RequiredArgsConstructor
public class StompHandler implements ChannelInterceptor {

private final JwtTokenProvider jwtTokenProvider;

@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);

if (StompCommand.CONNECT.equals(accessor.getCommand())) {
jwtTokenProvider.validateToken(Objects.requireNonNull(accessor.getFirstNativeHeader("Authorization")).substring(7));
// 헤더에서 JWT 추출
String token = accessor.getFirstNativeHeader("Authorization");


if (Objects.nonNull(token) && token.startsWith("Bearer ")) {
token = token.substring(7); // Bearer 부분을 제거

try {
// JWT 인증 수행
Authentication authentication = jwtTokenProvider.getAuthentication(token);

// StompAccessor에 사용자 정보를 추가 (STOMP 메시지 사용자 정보)
accessor.setUser(authentication);

// **SecurityContext에 인증 정보를 추가 (Spring Security에 인증 정보 추가)**
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);


} catch (Exception e) {
}
} else {
}
}
return message;
}
Expand Down
24 changes: 1 addition & 23 deletions src/main/java/B1G4/bookmark/config/WebSocketConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,7 @@ public void registerStompEndpoints(StompEndpointRegistry registry) {

@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);

if (StompCommand.CONNECT.equals(accessor.getCommand()) ||
StompCommand.SUBSCRIBE.equals(accessor.getCommand()) ||
StompCommand.SEND.equals(accessor.getCommand())) {

String token = accessor.getFirstNativeHeader("Authorization");
if (Objects.nonNull(token) && token.startsWith("Bearer ")) {
token = token.substring(7); // "Bearer " 제거
try {
Authentication authentication = jwtTokenProvider.getAuthentication(token);
accessor.setUser(authentication); // 사용자 정보 추가
} catch (Exception e) {
System.out.println("WebSocket Authentication failed: " + e.getMessage());
}
}
}
return message;
}
});
registration.interceptors(stompHandler); // StompHandler 추가
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,15 @@ private Jws<Claims> getClaims(String token) {
}

public Authentication getAuthentication(String token) {
try {
Long memberId = getId(token); // Extract member ID from JWT
User principal = new User(memberId.toString(), "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
return new UsernamePasswordAuthenticationToken(principal, token, principal.getAuthorities());
} catch (Exception e) {
throw new AuthException(ErrorStatus.AUTH_INVALID_TOKEN);
}
Claims claims = Jwts.parserBuilder()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(token)
.getBody();

String userId = claims.get("id", String.class);
User user = new User(userId, "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
return new UsernamePasswordAuthenticationToken(user, token, user.getAuthorities());
}

public void validateToken(String token) {
Expand Down
41 changes: 0 additions & 41 deletions src/main/java/B1G4/bookmark/web/controller/ChatController.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,47 +22,6 @@ public class ChatController {

private final ChatRoomServiceImpl chatRoomService;


// Swagger용 가짜 채팅방 입장 API
@Operation(
summary = "채팅방 입장",
description = "사용자가 특정 채팅방에 입장합니다. 이 경로는 WebSocket 동작을 설명하기 위해 추가된 가짜 API입니다." +
"클라이언트는 /app/chat/{chatRoomId}/join으로 메시지를 발행합니다. "+
"서버는 /topic/chat/{chatRoomId}로 구독 중인 모든 클라이언트에게 메시지를 브로드캐스트합니다."
)
@PostMapping("/swagger/chat/{chatRoomId}/join")
public BaseResponse<ChatMessageDTO> joinChatRoomSwagger(
@DestinationVariable @Parameter(
description = "입장할 채팅방의 ID" + "채팅방 ID는 공간 ID와 같습니다",
required = true
) Long chatRoomId,
@Parameter(name = "user", hidden = true)
@AuthUser Member member) {
ChatMessageDTO result = chatRoomService.handleJoinChatRoom(chatRoomId, member.getId());
return BaseResponse.onSuccess(result);
}

// Swagger용 가짜 메시지 전송 API
@Operation(
summary = "메시지 전송",
description = "사용자가 특정 채팅방에 메시지를 전송합니다. 이 경로는 WebSocket 동작을 설명하기 위해 추가된 가짜 API입니다." +
"클라이언트는 /app/chat/{chatRoomId}/send로 메시지를 발행합니다." +
"서버는 /topic/chat/{chatRoomId}로 구독 중인 모든 클라이언트에게 메시지를 브로드캐스트합니다."

)
@PostMapping("/swagger/chat/{chatRoomId}/send")
public BaseResponse<ChatMessageDTO> sendMessageSwagger(
@DestinationVariable @Parameter(
description = "메시지를 전송할 채팅방의 ID" + "채팅방 ID는 공간ID와 같습니다",
required = true
) Long chatRoomId,
@RequestBody @Parameter(
description = "전송할 메시지의 정보",
required = true
) ChatMessageDTO messageDTO) {
return BaseResponse.onSuccess(chatRoomService.handleSendMessage(chatRoomId, messageDTO));
}

// 채팅방 입장
/**
* 채팅방 입장
Expand Down
Loading