221205 TIL 내 채팅과 다른 사용자의 채팅 구분하기

오늘은 기존에 구현했던 채팅 기능을 더 보완하는 작업을 했다.

작업 목표는 카카오톡처럼 자신이 쓴 채팅과 상대방이 쓴 채팅의 말풍선 색이 다르게 보이도록 하고, 상대방의 채팅 말풍선에 상대방의 닉네임을 노출시키도록 하는 것이었다. 기존에는 누가 채팅을 치든 구분이 안되어서 익명 채팅방 같은 느낌이었는데 말풍선과 닉네임을 노출시켜 구분이 가도록 하는 것이었다.

 

우선 위와 같은 기능을 구현하기 위해 고민했던 건 자신이 쓴 채팅과 다른 사용자가 쓴 채팅을 어떻게 구별할지였다. 

우선 두 가지 방법을 떠올렸는데 아래와 같다.

1. 채팅을 보낼 때 아래와 같이 자신의 닉네임(writer)을 같이 보내게 했기 때문에 메시지를 받는 사용자도 writer가 누구인지 알 수 있어 메시지를 받을 때 writer와 현재 로그인한 사용자의 닉네임이 다르면 useState를 이용해 상태 값을 false 변경해서 채팅을 화면에 뿌릴 때 상태가 false이면 다른 사용자가 작성한 채팅이고 true이면 내가 작성한 채팅으로 구별하게 하는 방법이 첫 번째로 떠올린 방법이다.

 

2. 두 번째 방법은 채팅 메시지를 보낼때 로그인 한 사용자의 accessToken을 전달해 백엔드에서 해당 accessToken을 decode해서 사용자의 정보를 얻어 메시지를 보내는 dto에 사용자의 정보를 같이 전달해서 프론트엔드에서는 해당 메시지안의 사용자의 정보와 로그인한 사용자의 정보가 같으면 자신이 작성한 메시지이고 다르면 다른 사용자가 작성한 메시지로 구별하는 방법이 두번째 방법이다.

 

결론은 두번째 방법으로 구현을 했는데 첫 번째 방법으로 했었을때 문제가 있었기 때문이다.

첫번째 방법의 문제점을 간단히 말하면 내가 쓴 채팅은 빨간색으로 보이게 하고 상대방이 쓴 채팅은 노란색으로 보이게 했는데 내가 쓴 채팅과 상대방이 쓴 채팅이 구분이 되지 않았다. 전부 빨간색 아니면 노란색으로 나오는 문제가 있었다.

 

그래서 두 번째 방법으로 구현하기로 결정했다.

우선 채팅을 보낼 때 header에 accessToken을 같이 보낼 수 있는지부터가 관건이였다.  현재 채팅을 보낼때 React에서 StompClient를 이용해 send 하고 있었는데 send할때 header accessToken을 같이 전달하는 방법을 찾아봤는데 아래와 같이 보낼수 있다.

 

 

send의 {} 안에 header 값을 추가해줄 수 있다는 것을 알게 되었다.

 

기존에 메시지를 보낼 때 send방식은 위와 같이 {} 안에 아무것도 보내지 않고 있었다.

 

 

그래서 위와 같이 {} 안에 accessToken을 전달해주었더니 아래와 같이 send시 accessToken이 들어간 것을 확인할 수 있었다.

 

 

그러면 백엔드에서는 어떻게 이 accessToken을 받을 수 있지 생각을 해봤다.

기존에 사용하던 인증을 위한 인터셉터를 이용해서 accessToken을 가로채서 decode 해주고 @RequestAttribute를 이용하는 방법이 가능할지 실험을 해봤는데 인터셉터단에서 해당 header는 가져오지 못하는 것을 알게 되었다.

 

이후에 메시지에서 보낸 header값은 SimpMessageHeaderAccessor 클래스를 이용하면 send에서 보낸 header값을 가져올 수 있다는 것을 알게 되었다.

해당 클래스의 내장 메서드 중 get 관련된 메서드에서 헤더를 가져올 수 있을 것 같은 것을 찾아봤는데 getMessageHeader를 발견했고 이 메서드를 이용하면 header값 모두 가져올 수 있다는 것을 알게 되었다.

 

 

위 메서드의 값을 출력해보면 아래와 같다. 

 

nativeHeaders안에 메시지 안에 같이 전달해준 accessToken이 들어있는 것을 확인할 수 있다.

하지만 필요한 건 accessToken만 필요한데 getMessageHeader 메서드는 messageType, stompCommand, destination 등등 나에게 불필요한 정보들도 같이 온다. 여기서 nativeHeaders만 가져오는 방법을 고민했는데 자세히 보면 해당 메시지는 key와 value로 이루어져 있는 형태라는 것을 알 수 있었다. 그래서 get(key)로 value를 얻어올 수 있다.

 

getMessageHeader.get(“nativeHeaders”)를 이용해 Authorization 이하 토큰 값을 추출할 수 있다.

얻은 accessToken값을 decode 해서 사용자의 닉네임을 메시지 전달하는 dto에 같이 전달해서 프런트엔드에서 메시지 안의 닉네임과 현재 로그인한 닉네임이 같으면 내가 작성한 채팅으로 판단해서 말풍선 색을 다르게 해 주고 다를 시에는 다른 유저가 작성한 채팅으로 판단했다.

 

결과물은 아래와 같다.

왼쪽이 "훈이" 시점 채팅 화면이고 오른쪽이 "피까츄" 시점 채팅 화면이다. 

 

오늘은 계속해야겠다 해야겠다 생각만 했던 누가 작성한 채팅인지 구분하는 작업을 했는데 사실 채팅 기능 관련해서 좀 더 보완하고 싶은 부분들이 많지만 일단 해야 하는 관리자 기능부터 완성시키고 시간이 남으면 채팅 메시지를 서버에 저장하는 기능도 구현해보자!

 

참조 : https://stackoverflow.com/questions/25486889/websocket-stomp-over-sockjs-http-custom-headers