在websocket rails的wiki上,它有以下使用CanCan gem的示例。
这怎么行?对于正常的http请求,会发送一个带有标识用户的令牌的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
编辑:
在下面创建dispatcher
时,应发送包含Upgrade: websocket
和cookie的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');
这并不完全是原始数据,而是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,但这里重要的是,在创建连接时的握手中,客户端会发送cookie和其他信息,比如如果是某种http请求,服务器会接收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)订阅专用通道。
现在,需要理解的最重要的一点是,如果你订阅了一个频道,你就没有打开新的连接,你仍然会使用你现在要求订阅私人频道的同一个网络套接字,这也是你启动连接时发送cookie的同一网络套接字。
现在,如果你碰巧可以在方法路由(事件)上的websocket rails gem上设置断点,而不是文件dispatcher.rb,你会注意到,在后台,websocket rails使用faye websocket ruby来处理websocket连接,并且在请求中,你可以访问在websocket握手中发送的cookie。
路由将请求路由到websocketrails控制器AuthorizationController,在大多数情况下,它的代码如下:
if can?(:subscribe, message[:channel])
accept_channel current_user
else
deny_channel({:message => 'authorization failed!'})
end
因为它可以访问helper方法,所以同一个公共轨道控制器cancan?来自cancan的方法,将调用current_user助手,并且该方法将完全访问cookie。
因此,通道并不是websocket RFC中描述的东西,websocket只是一个可以用来发送任何数据的套接字,在这种情况下,公共和私有通道只是gem-websocket-trails的作者开发的一种通信行为,用于创建通信通道并向不同的客户端广播消息。
如果您进入websocketrails问题,您会注意到甚至有创建单向安全通道的请求:https://github.com/DanKnox/websocket-rails/issues/52
因此,这并不是说某人可以发送subscribe_to_private通道流并访问该通道,甚至在他们发送订阅流之前,他们必须通过http请求创建websocket连接,如rfc中所述,然后,通过该websocket连接,他们必须发送字节流,要求ruby gem订阅该通道,当他们这样做时,在rails服务器上,您可以自动访问创建连接时发送的那个websocket的cookie。