1. 序章

このチュートリアルでは、を使用してSpring WebSocketを使用して1人のユーザーにSTOMPメッセージを送信する方法について説明します。すべてのメッセージをすべてのユーザーにブロードキャストしたくない場合があるため、これは重要です。 さらに、これらのメッセージを安全な方法で送信する方法を示します。

WebSocketの概要については、thisの優れたチュートリアルで起動して実行する方法を確認してください。 また、セキュリティの詳細については、このの記事をチェックして、WebSocketの実装を保護してください。

2. キュー、トピック、およびエンドポイント

Spring WebSocketとSTOMPを使用して、メッセージの送信先とメッセージのサブスクライブ方法を3つの主な方法で確認できます。

  1. トピック–任意のクライアントまたはユーザーが利用できる一般的な会話またはチャットトピック
  2. キュー–特定のユーザーとその現在のセッション用に予約済み
  3. エンドポイント–汎用エンドポイント

次に、それぞれのコンテキストパスの例を簡単に見てみましょう。

  • 「/topic/movies」
  • 「/user/ queue/specific-user」
  • 「/secured/chat」

トピックとエンドポイントはこの機能をサポートしていないため、特定のユーザーにメッセージを送信するにはキューを使用する必要があることに注意してください

3. 構成

次に、特定のユーザーにメッセージを送信できるようにアプリケーションを構成する方法を学びましょう。

public class SocketBrokerConfig extends 
  AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/secured/user/queue/specific-user");
        config.setApplicationDestinationPrefixes("/spring-security-mvc-socket");
        config.setUserDestinationPrefix("/secured/user");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/secured/room").withSockJS();
    }
}

どのエンドポイントがシングルユーザー用に予約されているかを決定するので、ユーザーの宛先を含めるようにしてください。

また、すべてのキューとユーザーの宛先に「/ secureed」のプレフィックスを付けて、認証が必要になるようにします。 保護されていないエンドポイントの場合、「/ secureed」プレフィックスを削除できます(他のセキュリティ設定の結果として)。

pom.xml の観点からは、追加の依存関係は必要ありません。

4. URLマッピング

次のパターンに準拠するURLマッピングを使用して、クライアントがキューにサブスクライブするようにします。

"/user/queue/updates"

このマッピングは、UserDestinationMessageHandlerによってユーザーセッション固有のアドレスに自動的に変換されます。

たとえば、“ user123” という名前のユーザーがいる場合、対応するアドレスは次のようになります。

"/queue/updates-user123"

サーバー側では、次のURLマッピングパターンを使用してユーザー固有の応答を送信します。

"/user/{username}/queue/updates"

これも、クライアント側で既にサブスクライブしている正しいURLマッピングに変換されます。

したがって、ここでの必須成分は2つあることがわかります:

  1. 指定したユーザー宛先プレフィックス( AbstractWebSocketMessageBrokerConfigurer で構成)を付加します。
  2. マッピング内のどこかで「/queue」を使用します。

次のセクションでは、これを行う方法を正確に見ていきます。

5. convertAndSendToUser()を呼び出す

SimpmessagingTemplateまたはSimpMessageSendingOperationsからconvertAndSendToUser()を非静的に呼び出すことができます。

@Autowired
private SimpMessagingTemplate simpMessagingTemplate;

@MessageMapping("/secured/room") 
public void sendSpecific(
  @Payload Message msg, 
  Principal user, 
  @Header("simpSessionId") String sessionId) throws Exception { 
    OutputMessage out = new OutputMessage(
      msg.getFrom(), 
      msg.getText(),
      new SimpleDateFormat("HH:mm").format(new Date())); 
    simpMessagingTemplate.convertAndSendToUser(
      msg.getTo(), "/secured/user/queue/specific-user", out); 
}

お気づきかもしれません:

@Header("simpSessionId") String sessionId

@Headerアノテーションにより、インバウンドメッセージによって公開されたヘッダーにアクセスできます。たとえば、複雑なインターセプターを必要とせずに、現在のsessionIdを取得できます。 同様に、プリンシパルを介して現在のユーザーにアクセスできます。

重要なのは、この記事で採用しているアプローチにより、URLマッピングに関して@sendToUserアノテーションをさらにカスタマイズできることです。 そのアノテーションの詳細については、thisのすばらしい記事をご覧ください。

クライアント側では、JavaScriptで connect()を使用して SockJSインスタンスを初期化し、STOMP:を使用してWebSocketサーバーに接続します。

var socket = new SockJS('/secured/room'); 
var stompClient = Stomp.over(socket);
var sessionId = "";

stompClient.connect({}, function (frame) {
    var url = stompClient.ws._transport.url;
    url = url.replace(
      "ws://localhost:8080/spring-security-mvc-socket/secured/room/",  "");
    url = url.replace("/websocket", "");
    url = url.replace(/^[0-9]+\//, "");
    console.log("Your current session is: " + url);
    sessionId = url;
}

また、提供された sessionId にアクセスし、それを「 secure/room」URLマッピングに追加します。 これにより、ユーザー固有のサブスクリプションキューを動的かつ手動で提供できるようになります:

stompClient.subscribe('secured/user/queue/specific-user' 
  + '-user' + that.sessionId, function (msgOut) {
     //handle messages
}

すべてが設定されると、次のように表示されます。

 

そして私たちのサーバーコンソールで:

6. 結論

このトピックの詳細については、Springの公式ブログおよび公式ドキュメントを確認してください。

いつものように、この記事で使用されているコードサンプルは、GitHubから入手できます。