Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

채팅 시 인증 문제 #15

Open
MoonYeeun opened this issue Apr 19, 2021 · 1 comment
Open

채팅 시 인증 문제 #15

MoonYeeun opened this issue Apr 19, 2021 · 1 comment
Labels
🧐discussion 의논이 필요한 issue

Comments

@MoonYeeun
Copy link
Member

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

    @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 객체로 토큰이 받아와 지지 않는다.

  • 그러면 토큰을 받아올 수 있는 방법? @Header("Authorization") 헤더 이용

문제 2

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

  • @Header("Authorization") String authentication String 으로 가져와 진다.
  • 혹은 SimpMessageHeaderAccessor authentication 로 받아와서
    authentication.getNativeHeader("Authorization").get(0); 으로 가져올 수 있는데 결국 이것도 String임

문제 3

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

그럼 되는 방법 ?

  • 앞서 stomphandler 에서 토큰 검증했던 방식 그대로 사용하면 유저아이디 가져올 순 있음...(매우 비효율적이고...별로임..)
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();
}

고민해봐야할 사항

  • 문제 3에서 String 으로 받아온 토큰을 어떻게 우리가 원하는 대로 바꿀 수 있을까
  • 문제 2에서 헤더 값을 String 말고 다르게 받아올 수 있나
  • StompHandler에서 채팅 메세지에 접근하여 유저아이디 값 넣어주기 ...(? 아마 위와 같은 비슷한 상황 발생할 거 같음)
  • StompHandler에서 토큰 검증하는 로직을 채팅컨트롤러에서도 쓸 수 있게 어떻게 잘 만들어보기
  • 기타 다른 방법..찾ㄱ ㅣ
@MoonYeeun MoonYeeun added the 🧐discussion 의논이 필요한 issue label Apr 19, 2021
@inspirit941
Copy link
Member

현재 작업결과

메시지 수신 시

  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정보를 유지하는 방법을 알아내야 함.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🧐discussion 의논이 필요한 issue
Projects
None yet
Development

No branches or pull requests

2 participants