websocket-rails gem和身份验证

use*_*220 1 ruby-on-rails websocket ruby-on-rails-3 ruby-on-rails-3.2

在websocket-rails 的wiki上,它使用CanCan gem 进行以下示例.

这怎么办?使用正常的http请求,会发送一个cookie,该cookie具有标识用户的标记,但是使用websockets原始数据并且没有发送cookie,因此服务器如何识别用户使用CanCan gem的用户?

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
Run Code Online (Sandbox Code Playgroud)

编辑:

在下面dispatcher创建的时候应该发送一个包含Upgrade: websocketcookie 的http请求.但是在下一行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');
Run Code Online (Sandbox Code Playgroud)

ror*_*rra 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
Run Code Online (Sandbox Code Playgroud)

它通过套接字作为字节流发送,但是同样的事情发生在一个普通的http请求中,然而,

如果检查使用rails-websocket创建的请求,则在js代码上运行时

var dispatcher = new WebSocketRails('localhost:3000/websocket');
Run Code Online (Sandbox Code Playgroud)

您将看到通过网络进行连接的请求

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
Run Code Online (Sandbox Code Playgroud)

所以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
Run Code Online (Sandbox Code Playgroud)

如果在authorize_channels方法上放置断点,您将看到所有cookie都像一个常见的http请求一样.

有关websocket工作原理和方式的更多信息,您可以阅读RFC,但重要的是在创建连接时的握手中,客户端会发送cookie以及其他信息,例如它是某种http请求,服务器接收websocket请求,通过检查cookie来验证用户身份,并打开保持打开的连接作为全双工通信的套接字,或者因为凭据无效而关闭连接.


我不确定我是否理解你的问题.公共页面请求和Web套接字之间的主要区别在于,Web套接字是一个用户http握手以启动连接的套接字.

在您的代码中,这些行使用cookie发送http请求,服务器接受连接.

// connect to server like normal
var dispatcher = new WebSocketRails('localhost:3000/websocket');
Run Code Online (Sandbox Code Playgroud)

所以此时你有一个全双工套接字(这意味着服务器或客户端可以通过它发送数据而不会发生冲突).任意数据.

然后在下一个代码:

// subscribe to the channel
var private_channel = dispatcher.subscribe_private('channel_name');
Run Code Online (Sandbox Code Playgroud)

客户端要求服务器(通过websocket上的活动连接)订阅私有通道.

现在,最重要的一点是,如果你订阅了一个频道,你没有打开一个新的连接,你仍然会使用你现在要求订阅私人频道的同一个Websocket,这是您在开始连接时发送cookie的相同websocket.

现在,如果偶然你可以在websocket-rails gem上设置一个断点,没有文件dispatcher.rb,在方法路由(事件)上,你会发现在引擎盖下,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
Run Code Online (Sandbox Code Playgroud)

并且因为它可以访问辅助方法相同的共同轨道控制器,康康?来自cancan的方法将调用current_user帮助程序,此方法将具有对cookie的完全访问权限.

因此,渠道不是websocket RFC中描述的内容,websocket只是一个可用于发送任何数据的套接字,在这种情况下,公共和私有渠道只是由作者开发的通信行为. gem websocket-rails用于创建通信和向不同客户端广播消息的通道.

如果你进入websocket-rails问题,你会发现甚至有创建单向安全通道的请求:https://github.com/DanKnox/websocket-rails/issues/52

所以它不像有人可以发送一个subscribe_to_private频道流并获得对该频道的访问权限,在他们甚至可以发送流进行订阅之前,他们必须通过http请求创建websocket连接,如rfc所述,然后,在那个websocket连接上,他们必须发送字节流,要求ruby gem订阅该频道,当他们这样做时,在rails服务器上你可以自动访问连接时发送的websocket的cookie.创建了.