witherview / witherview_backend

🎯 위더뷰 Backend
https://api.witherview.com/swagger-ui.html
2 stars 0 forks source link

채팅 시 인증 문제 #15

Open MoonYeeun opened 3 years ago

MoonYeeun commented 3 years ago

기존에 작성된 채팅 컨트롤러

    @MessageMapping("/chat.room")
    public void message(@Payload @Valid ChatDTO.MessageDTO message, Authentication authentication) throws JsonProcessingException {
        var userId = AuthTokenParsing.getAuthClaimValue(authentication, "userId");
        message.setUserId(userId);
        chatProducer.sendChat(message);
    }

문제 1

Authentication 객체로 토큰이 받아와 지지 않는다.

문제 2

@Header("Authorization") Authentication authentication 이렇게 토큰 받아와 지지 않음

문제 3

String으로 받아온 토큰을 Authentication 객체 혹은 JwtAuthenticationToken 객체로 만드려고 시도해봤으나 실패

그럼 되는 방법 ?

var bearerToken = authentication.replace("Bearer ", "");

var jwsAuthToken = new JWSAuthenticationToken(bearerToken);
String tokenString = (String) jwsAuthToken.getCredentials();

var userId = "";
try {
    KeycloakDeployment resolve = keycloakSpringBootConfigResolver.resolve(null);
    AccessToken accessToken = AdapterTokenVerifier.verifyToken(tokenString, resolve);
    userId = (String) accessToken.getOtherClaims().get("userId");
} catch (VerificationException e) {
    e.printStackTrace();
}

고민해봐야할 사항

inspirit941 commented 3 years ago

현재 작업결과

메시지 수신 시

  1. 웹소켓으로 들어오는 메시지 - 컨트롤러에서 @MessageMapping으로 받는 영역 - 에도 헤더에 jwt 토큰을 넣도록 함.
  2. 들어온 header의 토큰값은 @header("Authorization") 형태의 string 문자열이 된다.
  3. keycloak의 resolver를 적용해서 해당 토큰을 풀어내고, 풀어낸 토큰의 userId값을 추출해서 사용자를 확인한다.
  4. 어떤 사용자가 메시지를 보냈는지는 userId로 특정하게 된다.

메시지 송신 시

stomphandler의 presend에서 웹소켓 헤더의 jwt 토큰을 검증한다. 즉 헤더에 토큰값이 올바르게 입력되지 않으면 메시지 자체가 전송되지 않는 구조.

문제점

  1. 일반적으로는 http로 처음 socket connection을 맺을 때에는 header에 인증정보를 넣지만, websocket으로 데이터를 송 / 수신할 때에는 굳이 검증 로직을 넣지 않는다. 매번 websocket으로 메시지를 보낼 때마다 헤더에 jwt 문자열이 포함되기 때문에
    • 메시지 헤더의 크기가 본문인 채팅보다 더 커진다.
    • 채팅 횟수가 증가할 경우, 매번 헤더의 jwt 토큰을 확인하는 데 걸리는 시간. (scalable할 수 있는가?)

-> 이렇게 된 이유는 http + websocket으로 connection을 맺을 때, 연결된 사용자의 고유값 (userId) 정보를 stateful하게 내부적으로 관리하는 방법을 아직 모르기 때문.

-> 일단은 "허용되지 않은 사용자가 방에 메시지를 보내는 상황"을 최대한 막기 위해 이런 방식을 사용했지만, 추후에 http + websocket 연결 시 userId정보를 유지하는 방법을 알아내야 함.