기본 콘텐츠로 건너뛰기

socketcluster tutorial - 6. 미들웨어 및 인증 (Middleware and authorization)

미들웨어 및 인증


SocketCluster를 사용하면 클라이언트는 JavaScript를 사용하여 특정 채널로 데이터를 청취하고 발행하여 메시지를 서로 공유할 수 있습니다. 기본적으로 누구나 자신이 좋아하는 채널에 데이터에 수신하고 게시할 수 있습니다. 일부 시스템에서는 이것이 문제가 되지 않지만 대부분의 시스템은 사용자가 서로 상호 작용할 수 있는 방법을 규제하기 위해 어느 정도의 접근 제어가 필요합니다. 대부분의 시스템은 적절한 접근 권한을 시행하기 위해 연결을 인증하고 권한을 부여하는 방법이 필요합니다. 미들웨어 기능은 이러한 모든 작업을 수행할 수 있는 깔끔한 중앙 집중식 방식을 제공합니다.

SocketCluster에서 모든 실시간 이벤트는 서버에서 처리하기 전에 미들웨어 기능을 통과해야 합니다. SocketCluster는 다양한 종류의 상호 작용을 처리할 수 있는 다양한 종류의 미들웨어 라인을 제공합니다. 가장 유용한 미들웨어 라인은 워커 프로세스에 있지만 로드 밸런서(HTTP 용)에 의해 노출되는 미들웨어 라인이 있습니다. 이 튜토리얼에선 워커(실시간) 미들웨어에만 초점을 맞춥니다.

워커는 실시간 scServer 객체를 통해 미들웨어를 노출합니다. 이 객체는 worker.getSCServer()를 사용하여 액세스 할 수 있습니다.

미들웨어 기능을 서버에 추가하려면 다음을 사용해야 합니다.
scServer.addMiddleware (middlewareType, middlewareFunction);
scServer에서 사용할 수있는 미들웨어 유형은 다음과 같습니다.
scServer.MIDDLEWARE_HANDSHAKE
scServer.MIDDLEWARE_SUBSCRIBE
scServer.MIDDLEWARE_PUBLISH_IN
scServer.MIDDLEWARE_PUBLISH_OUT
scServer.MIDDLEWARE_EMIT
middlewareFunction에 전달한 req인자는 사용한 미들웨어의 종류에 따라 다릅니다. 다음 예제의 err객체는 JavaScript의 Error객체를 상속한 사용자 정의 클래스를 기반으로 합니다. 서버에서 스택 트레이스를 사용하지 않는 경우 폼에서 {name: 'MyCustomError', message: 'This is a custom error'} (또는 추가 사용자 정의 속성을 사용하여)와 같은 일반 객체를 next(err)에게 전달할 수 있습니다. 다음은 각 종류의 미들웨어를 사용하는 방법을 보여주는 몇 가지 샘플 코드 스니펫입니다.

핸드쉐이크

// WebSocket 핸드쉐이크용
wsServer.addMiddleware(wsServer.MIDDLEWARE_HANDSHAKE,
  function (req, next) {
    // ...
    if (...) {
      next() // Allow
    } else {
      var err = new MyCustomHandshakeFailedError('Handshake failed');
      next(err); // Block
      // next(true); // 서버 측에서 경고하지 않고 조용히 next() 블록에 true를 전달합니다.
    }
  }
);

구독하기

기본 인증 토큰 만료 오류로 실패합니다.
// Error 객체에 사용자 정의 속성을 가질 수 있습니다.
// 서버 측에서 경고를하지 않고 조용히 next () 블록에 true를 전달합니다.
wsServer.addMiddleware(wsServer.MIDDLEWARE_SUBSCRIBE,
  function (req, next) {
    // ...
    if (req.authTokenExpiredError) {
      next(req.authTokenExpiredError); // 기본 인증 토큰 기간 만료 오류로 실패
    } else if (...) {
      next() // Allow
    } else {
      var socketId = req.socket.id;
      var err = new MyCustomSubscribeFailedError(socketId + ' cannot subscribe to channel ' + req.channel);
      // You can have custom properties on your Error object.
      err.code = 1234;
      next(err); // Block
      // next(true); // 서버 측에서 경고하지 않고 조용히 next() 블록에 true를 전달합니다.
    }
  }
);

발행

SC는 게시를 위해 두 가지 미들웨어 라인을 지원합니다. MIDDLEWARE_PUBLISH_IN은 게시한 메시지를 처리한 후 (개별 소켓으로 보내기 직전) MIDDLEWARE_PUBLISH_OUT가 캡처한 메시지를 처리하는 동안 브로커에 도달하기 전에 서버에 도달할 때 인바운드 메시지를 캡처합니다. MIDDLEWARE_PUBLISH_OUT을 사용하면 메시지가 특정 소켓에 도달하는 것을 차단할 수 있습니다. 이 경우에는 메시지를 게시한 소켓이 자신의 메시지를 받지 않도록 메시지와 미들웨어를 설계할 수 있습니다.

Publish In

wsServer.addMiddleware(wsServer.MIDDLEWARE_PUBLISH_IN,
  function (req, next) {
    // ...
    if (...) {
      next() // Allow
    } else {
      var err = MyCustomPublishInFailedError(req.socket.id + ' cannot publish channel ' + req.channel);
      next(err); // Block
      // next(true); // 서버 측에서 경고하지 않고 조용히 next() 블록에 true를 전달합니다.
    }
  }
);

Publish out

wsServer.addMiddleware(wsServer.MIDDLEWARE_PUBLISH_OUT,
  function (req, next) {
    // ...
    if (...) {
      next() // Allow
    } else {
      var err = MyCustomPublishOutFailedError('Blocked publishing message out to ' + req.socket.id);
      next(err); // Block with notice
      // next(true); // 서버 측에서 경고하지 않고 조용히 next() 블록에 true를 전달합니다.
    }
  }
);

전송하기

wsServer.addMiddleware(wsServer.MIDDLEWARE_EMIT,
  function (req, next) {
    // ...
    if (...) {
      next() // Allow
    } else {
      var err = MyCustomEmitFailedError(req.socket.id + ' is not allowed to emit event ' + req.event);
      next(err); // Block
      // next(true); // 서버 측에서 경고하지 않고 조용히 next() 블록에 true를 전달합니다.
    }
  }
);
next() 함수는 언제든지 (비동기가 좋습니다) 호출할 수 있지만, 결과적으로 호출하는 것을 확인해야 합니다. 그렇지 않으면 클라이언트의 subscribe/ publish/emit 액션이 단순 타임아웃이나 클라이언트 쪽에서 원인을 알 수 없는 타임아웃 오류를 발생할 것입니다. 클라이언트가 뭔가를 하지 못하도록 차단하려면 명시적 오류를 주는 것이 더욱 다루기 쉽습니다.

댓글

이 블로그의 인기 게시물

세상 간단한 https(+secured websocket): Caddy

nginx, apache2 같은 걸로 매번 certbot 연동을 통해 https 하는게 지겨워서 알아보니 Caddy라는게 있더라. 설치법은 강하게 크기 위해 알아서 해본다. # cat /etc/caddy/Caddyfile your.shitty.site:8123 {   proxy / localhost:9123 {     websocket     transparent   } } 이건 외부에서 8123으로 들어오는 걸 내부적으로 9123로 맞춰서 https 맞춰주는 reverse proxy. 만일 port를 생략하면 # cat /etc/caddy/Caddyfile your.shitty.site {   proxy / localhost:9123 {     websocket     transparent   } } 기본포트인 443으로 되어 https://your.shitty.site 로 접속이 된다. 요새 말썽이던 cloudflare 버리고 netlify domain이랑 caddy를 쓰니까 앓던 이가 빠진 느낌. 이 조합은 당분간 계속 써야겠다 싶다.

저지연 오디오 생성 LLVC 사용기

https://github.com/KoeAI/LLVC 써봄 CUDA 11.8 버전 쓰고 있어 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 VC 없어서 설치 https://wikidocs.net/168848 참조 FAIRSEQ 관련 오류 https://github.com/facebookresearch/fairseq/issues/2908 pip install editdistance  설치 No CUDA runtime is found, using CUDA_HOME='C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8' 오류 멀쩡하게 있는데 안됨. pip install torch==2.1.0+cu118 torchvision==0.16.0+cu118 torchaudio==2.1.0+cu118 --extra-index-url https://download.pytorch.org/whl/cu118 다시 설치 set DISTUTILS_USE_SDK=1 이게 문젠가 설정하고 재도전 Using cached ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl (118 kB) Building wheels for collected packages: fairseq   Building wheel for fairseq (pyproject.toml) ... error   error: subprocess-exited-with-error   × Building wheel for fairseq (pyproject.toml) did not run successfully.   │ exit code: 1   ╰─> [1829 lines of output]       No CUDA runtime is found, usi...