JWT 필터로 유저를 검증하고 유저 정보를 추출했었는데 STOMP는 HTTP 위에서 동작하는 것이 아니기 때문에 HTTP 헤더를 받아올 수 없었음.
→ STOMP 메세지 보낼 때 headers 옵션을 추가하고 JWT를 보낸 후 컨트롤러에서 @Header 어노테이션을 통해 헤더 수신. 이후 서비스에서 JWT로 유저 정보 추출
function sendMessage() {
const content = messageInput.val();
stompClient.publish({
destination: `/app/chat-rooms/${currentRoomId}/messages`,
headers: {Authorization: getToken()},
body: JSON.stringify({'content': content})
});
messageInput.val("");
}
@MessageMapping("/chat-rooms/{roomId}/messages")
@SendTo("/topic/chat-rooms/{roomId}")
public GetMessageResponse sendMessage(
@DestinationVariable Long roomId,
CreateMessageRequest request,
@Header("Authorization") String token
) throws Exception {
Thread.sleep(500); // 지연 시뮬레이션
return messageService.createMessage(roomId, request, token);
}
하지만 기존에 필터에서 처리되는 검증 작업이 이루어지지 않았고 해당 검증을 서비스에서 전부 처리하기엔 유지보수적인 측면에서 안 좋다고 판단함.
STOMP에도 필터와 비슷한 역할을 하는 Interceptor를 알게 됐고 이를 통해 해결
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor headerAccessor = MessageHeaderAccessor.getAccessor(message,
StompHeaderAccessor.class);
if (headerAccessor != null && headerAccessor.getCommand() == StompCommand.SEND) {
String token = headerAccessor.getFirstNativeHeader("Authorization");
if (token != null) {
jwtUtil.validateToken(token);
}
}
return message;
}
});
}