在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');发布于 2013-03-01 16:06:28
它不完全是原始数据,它是http协议的升级,它是一个保持连接打开的套接字,如果你查看wikipedia上的文档,在创建连接时关于握手请求,有一个从客户端发送的信息流,以及一个来自服务器的应答。
因此,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因此,cookies正在发送,最重要的是,在您的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方法上设置了断点,您将看到您拥有所有的cookies,就好像它是一个普通的http请求一样。
有关websocket工作内容和工作方式的更多信息,您可以阅读RFC,但这里重要的是,当创建连接时,在握手时,客户端发送cookies以及其他信息,例如它是否是某种http请求,服务器接收websocket请求,通过检查cookies对用户进行身份验证,然后它要么打开作为全双工通信套接字打开的连接,要么因为凭据无效而关闭连接。
我不确定我是否理解了你的问题。公共页面请求和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 )上设置断点,那么您将注意到,在幕后,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而且因为它可以访问与普通rails控制器相同的辅助方法,所以cancan?方法将调用current_user帮助器,并且此方法将具有对cookies的完全访问权限。
所以通道不是websocket RFC中描述的东西,websocket只是一个可以用来发送任何数据的套接字,在这种情况下,公共和私有通道只是gem websocket-rails的作者开发的一种通信行为,用于创建通信通道并向不同的客户端广播消息。
如果您深入研究websocket-rails问题,您会注意到甚至有创建单向安全通道的请求:https://github.com/DanKnox/websocket-rails/issues/52
所以这不像是有人可以发送subscribe_to_private通道流并访问通道,在他们可以发送订阅流之前,他们必须通过http请求创建websocket连接,然后,通过该websocket连接,他们必须发送字节流,请求ruby gem订阅该通道,当他们这样做时,在rails服务器上,您可以自动访问该websocket的cookies,这些cookies是在创建连接时发送的。
https://stackoverflow.com/questions/15049262
复制相似问题