问题
I've found a wonderful ActionCable gem, which is a good solution for SPA.
I want to send only the html
, css
and js
assets, all other connections will be implemented through ActionCable
. It's not difficult to exchange strings or integers, but how can I login through ActionCable?
回答1:
From the 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
So it looks like you could insert your own find_verified_user
logic here. The reject_unauthorized_connection
method lives in lib/action_cable/connection/authorization.rb
for reference.
From 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.
With this in mind it would likely be a real pain not to just use a normal web login flow to set your auth cookie, delivering your SPA after the authentication step, but hopefully this can give you some pointers.
回答2:
FYI, if you have devise
already installed in your application, then you can use the environment variable set by warden
to find the authenticated user
. For every authenticated user warden stores the user object in environment var. Every request is authenticated by warden
middleware.
Note: this env is different from 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
If you have not used devise
then, here is another solution. Precondition is, you will have to set a signed cookie called user_id
in your sessions_controller
or something like that.
eg
cookies.signed[:user_id] = current_user.id
and for connection:
# 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
回答3:
The solution is to use HTTP authorization token. It's simple, widespread and obvious. This article helped me a lot
来源:https://stackoverflow.com/questions/32025897/authenticating-actioncable-connections