验证 ActionCable 连接
Authenticating ActionCable connections
我找到了一个很棒的 ActionCable gem,这是一个很好的 SPA 解决方案。
我只想发送 html
、css
和 js
资产,所有其他连接将通过 ActionCable
实现。交换字符串或整数并不难,但是如何通过 ActionCable 登录?
来自Readme
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
end
protected
def find_verified_user
if current_user = User.find(cookies.signed[:user_id])
current_user
else
reject_unauthorized_connection
end
end
end
end
看来您可以在此处插入您自己的 find_verified_user
逻辑。 reject_unauthorized_connection
方法存在于 lib/action_cable/connection/authorization.rb
以供参考。
来自Heroku:
[authentication] can be done in a variety of ways, as WebSockets will
pass through standard HTTP headers commonly used for authentication.
This means you could use the same authentication mechanism you’re
using for your web views on WebSocket connections as well.
Since you cannot customize WebSocket headers from JavaScript, you’re limited to
the “implicit” auth (i.e. Basic or cookies) that’s sent from the
browser. Further, it’s common to have the server that handles
WebSockets be completely separate from the one handling “normal” HTTP
requests. This can make shared authorization headers difficult or
impossible.
考虑到这一点,如果不使用普通的 Web 登录流程来设置您的身份验证 cookie,在身份验证步骤后交付您的 SPA,这可能会是一个真正的痛苦,但希望这可以给您一些指示。
解决方案是使用 HTTP 授权令牌。它简单、广泛且显而易见。 This article对我帮助很大
仅供参考,如果您的应用程序中已经安装了 devise
,那么您可以使用 warden
设置的环境变量来查找 authenticated user
。对于每个经过身份验证的用户,监狱长将用户对象存储在环境变量中。每个请求都由 warden
中间件进行身份验证。
注意:这个env不同于ENV
。
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user_from_env
end
private
def find_verified_user_from_env
# extracting `user` from environment var
current_user = env['warden'].user
if current_user
current_user
else
reject_unauthorized_connection
end
end
end
end
如果你还没有用过devise
那么,这里有另一种解决方法。前提是,您必须在 sessions_controller
或类似的东西中设置一个名为 user_id
的签名 cookie。
例如
cookies.signed[:user_id] = current_user.id
和连接:
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user_from_cookies
end
private
def find_verified_user_from_cookies
current_user = User.find_by_id(cookies.signed[:user_id])
if current_user
current_user
else
reject_unauthorized_connection
end
end
end
end
我找到了一个很棒的 ActionCable gem,这是一个很好的 SPA 解决方案。
我只想发送 html
、css
和 js
资产,所有其他连接将通过 ActionCable
实现。交换字符串或整数并不难,但是如何通过 ActionCable 登录?
来自Readme
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
end
protected
def find_verified_user
if current_user = User.find(cookies.signed[:user_id])
current_user
else
reject_unauthorized_connection
end
end
end
end
看来您可以在此处插入您自己的 find_verified_user
逻辑。 reject_unauthorized_connection
方法存在于 lib/action_cable/connection/authorization.rb
以供参考。
来自Heroku:
[authentication] can be done in a variety of ways, as WebSockets will pass through standard HTTP headers commonly used for authentication. This means you could use the same authentication mechanism you’re using for your web views on WebSocket connections as well.
Since you cannot customize WebSocket headers from JavaScript, you’re limited to the “implicit” auth (i.e. Basic or cookies) that’s sent from the browser. Further, it’s common to have the server that handles WebSockets be completely separate from the one handling “normal” HTTP requests. This can make shared authorization headers difficult or impossible.
考虑到这一点,如果不使用普通的 Web 登录流程来设置您的身份验证 cookie,在身份验证步骤后交付您的 SPA,这可能会是一个真正的痛苦,但希望这可以给您一些指示。
解决方案是使用 HTTP 授权令牌。它简单、广泛且显而易见。 This article对我帮助很大
仅供参考,如果您的应用程序中已经安装了 devise
,那么您可以使用 warden
设置的环境变量来查找 authenticated user
。对于每个经过身份验证的用户,监狱长将用户对象存储在环境变量中。每个请求都由 warden
中间件进行身份验证。
注意:这个env不同于ENV
。
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user_from_env
end
private
def find_verified_user_from_env
# extracting `user` from environment var
current_user = env['warden'].user
if current_user
current_user
else
reject_unauthorized_connection
end
end
end
end
如果你还没有用过devise
那么,这里有另一种解决方法。前提是,您必须在 sessions_controller
或类似的东西中设置一个名为 user_id
的签名 cookie。
例如
cookies.signed[:user_id] = current_user.id
和连接:
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user_from_cookies
end
private
def find_verified_user_from_cookies
current_user = User.find_by_id(cookies.signed[:user_id])
if current_user
current_user
else
reject_unauthorized_connection
end
end
end
end