1

websocket-railsのwikiには、 CanCangemを使用した次の例があります。

これはどのように機能しますか?通常のhttpリクエストでは、ユーザーを識別するトークンを持つCookieが送信されますが、WebSocketでは生データが送信され、Cookieは送信されません。サーバーは、CanCangemを使用してユーザーが誰であるかをどのように識別しますか。

class AuthorizationController < WebsocketRails::BaseController
  def authorize_channels
    # The channel name will be passed inside the message Hash
    channel = Channel.find_by_name message[:channel]
    if can? :subscribe, channel
      accept_channel current_user
    else
      deny_channel {:message => 'authorization failed!'}
    end
  end
end

編集:

以下では、Cookieだけでなくをdispatcher含むhttpリクエストを送信する必要があるが作成されます。Upgrade: websocketしかし、次の行subscribe_privateではWebSocket接続が作成されていないため、httpリクエストではなく、おそらくCookieに自動的にアクセスできません。

// connect to server like normal
var dispatcher = new WebSocketRails('localhost:3000/websocket');

// subscribe to the channel
var private_channel = dispatcher.subscribe_private('channel_name');
4

1 に答える 1

5

それは正確には生データではなく、接続を開いたままにするソケットへのhttpプロトコルのアップグレードです。ウィキペディアのドキュメントを確認すると、接続が作成されているときのハンドシェイク要求で、送信される情報のストリームがありますクライアントからの応答、およびサーバーからの応答。

したがって、websocket 接続要求の例は次のようになります。

GET /mychat HTTP/1.1
Host: server.example.com 
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13
Origin: http://example.com

これはソケットを介してバイトのストリームとして送信されますが、一般的な http 要求でも同じことが起こりますが、

rails-websocketで作成したリクエストを確認すると、jsで実行すると以下のコード

var dispatcher = new WebSocketRails('localhost:3000/websocket');

ネットワークを介した接続のリクエストが

GET /websocket HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,es-ar;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://localhost:3000
Sec-WebSocket-Key: dRpM9EesBFdk3SOH2QL/Tw==
Cookie: __utma=111872281.1938357651.1354053248.1355759500.1357797379.3; __utmz=111872281.1354053248.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); hblid=T1PaqE0vcRC9zDYrpFoBo5RD91766581; olfsk=olfsk5917359536568161; remember_admin_user_token=BAhbB1sGaQlJIiIkMmEkMTAkV0VhZzJaeXg3SzZFQWMzVUdPLktaTwY6BkVU--f84238cbbcb767e075117603de67f56a7150eb97; _stack_session=BAh7CEkiD3Nlc3Npb25faWQGOgZFRkkiJTg0NGIwNzZmNWUyZjFiNTMwZDkwMWUyMGFiODMxOGE3BjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMWxIS1FHUjg1b2pDbjFybFY4RW8yemtzRWtVQUdHY1BxTGxtdzBWOFdBN009BjsARkkiE3VzZXJfcmV0dXJuX3RvBjsARiIZL2hvbWUvcHJpdmF0ZV9hY3Rpb24%3D--e4823c74756cf70af0675323fb752b1f87064f09
Connection: keep-alive, Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket

したがって、Cookie は AuthorizationController で送信されます。最も重要なことは次のとおりです。

class AuthorizationController < WebsocketRails::BaseController
  def authorize_channels
    # The channel name will be passed inside the message Hash
    channel = Channel.find_by_name message[:channel]
    if can?(:subscribe, channel)
      accept_channel current_user
    else
      deny_channel({:message => 'authorization failed!'})
    end
  end
end

authorize_channels メソッドにブレークポイントを設定すると、すべての Cookie が一般的な http リクエストであるかのように表示されます。

Websocket がどのように機能するかについての詳細は、RFCを参照してください。ただし、ここで重要なことは、接続が作成されたときのハンドシェイクで、クライアントが、何らかの http であるかのように、他の情報とともに Cookie を送信することです。要求、サーバーは websocket 要求を受信し、Cookie をチェックしてユーザーを認証し、全二重通信用のソケットとして開いたままの接続を開くか、資格情報が無効であるため接続を閉じます。


あなたの質問を理解しているかどうかわかりません。一般的なページ リクエストと Web ソケットの主な違いは、Web ソケットは、接続を開始するために http ハンドシェイクを使用するソケットであることです。

コードでは、これらの行は Cookie を含む http 要求を送信し、サーバーは接続を受け入れます。

// connect to server like normal
var dispatcher = new WebSocketRails('localhost:3000/websocket');

したがって、この時点で、全二重ソケットが得られます (これは、サーバーまたはクライアントのいずれかが競合することなくデータを送信できることを意味します)。任意のデータ。

次に、次のコードで:

// subscribe to the channel
var private_channel = dispatcher.subscribe_private('channel_name');

クライアントはサーバーに (有効な接続を介して、Websocket を介して) プライベートなチャネルにサブスクライブするように要求しています。

ここで理解しておくべき主な重要なことは、チャネルにサブスクライブした場合、新しい接続を開くのではなく、プライベートチャネルへのサブスクライブを求めているのと同じ Websocket を引き続き使用することです。接続を開始したときに Cookie を送信したのと同じ WebSocket。

ここで、たまたま websocket-rails gem にブレークポイントを設定できた場合、dispatcher.rb ファイルではなくメソッド route(event) にブレークポイントを設定できた場合、内部では websocket-rails が faye-websocket-ruby を使用して処理していることに気付くでしょう。 Websocket 接続、および要求内で、Websocket ハンドシェイクで送信された Cookie にアクセスできること。

ルートはリクエストを websocket-rails コントローラー AuthorizationController にルーティングします。ほとんどの場合、次のようなコードがあります。

if can?(:subscribe, message[:channel])
  accept_channel current_user
else
  deny_channel({:message => 'authorization failed!'})
end

また、コモンレールコントローラと同じヘルパーメソッドにアクセスできるため、cancan? cancan のメソッドは current_user ヘルパーを呼び出し、このメソッドは Cookie に完全にアクセスできます。

したがって、チャネルは websocket RFC で説明されているものではありません。websocket は、任意のデータを送信するために使用できる単なるソケットです。この場合、パブリック チャネルとプライベート チャネルは、. gem websocket-rails を使用して、通信チャネルを作成し、さまざまなクライアントにメッセージをブロードキャストします。

websocket-rails の問題を調べてみると、一方向の安全なチャネルを作成するようにという要求さえあることがわかります: https://github.com/DanKnox/websocket-rails/issues/52

したがって、誰かが subscribe_to_private チャネルのストリームを送信してチャネルへのアクセスを取得できるわけではなく、サブスクリプションのためにストリームを送信する前に、rfc で説明されているように、http 要求によって Websocket 接続を作成する必要があります。その Websocket 接続を介して、ruby gem にそのチャネルをサブスクライブするように要求するバイト ストリームを送信する必要があります。これを行うと、Rails サーバー上で、接続時に送信されたその Websocket の Cookie に自動的にアクセスできます。作成されました。

于 2013-03-01T08:06:27.967 に答える