问题
Why am I not able to retrieve current_user
inside my channel or how should I retrieve current_user
?
What do I use?
- Rails 5.0.1 --api (I do NOT have any views NOR use coffee)
- I use react-native app to test this (Works fine WITHOUT authorization)
- I do NOT use devise for auth (I use JWT instead using Knock, so no cookies)
Trying to get current_user
inside my ActionCable channel as described in rubydoc.info
The code looks like
class MessageChannel < ApplicationCable::Channel
identified_by :current_user
def subscribed
stream_from 'message_' + find_current_user_privileges
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
protected
def find_current_user_privileges
if current_user.has_role? :admin
'admin'
else
'user_' + current_user.id
end
end
end
And running it, I get this error:
[NoMethodError - undefined method `identified_by' for MessageChannel:Class]
And if I remove identified_by :current_user
, I get
[NameError - undefined local variable or method `current_user' for #<MessageChannel:0x7ace398>]
回答1:
If you see the doc you provided, you will know that identified_by
is not a method for a Channel
instance. It is a method for Actioncable::Connection
.
From Rails guide for Actioncable Overview, this is how a Connection
class looks like:
#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
private
def find_verified_user
if current_user = User.find_by(id: cookies.signed[:user_id])
current_user
else
reject_unauthorized_connection
end
end
end
end
As you can see, current_user
is not available here. Instead, you have to create a current_user
here in connection.
The websocket server doesn't have a session, but it can read the same cookies as the main app. So I guess, you need to save cookie after authentication.
回答2:
if u are using devise gems in rails, Please replace this function:
def find_verified_user # this checks whether a user is authenticated with devise
if verified_user = env['warden'].user
verified_user
else
reject_unauthorized_connection
end
end
I hope this will help u.
回答3:
Well, in theory:
- You have access to the cookies in the
ActiveCable::Connection
class. - You can set and receive
cookies.signed
andcookies.encrypted
- Both the application and ActionCable share same configuration, therefore they share same `secret_key_base'
So, if you know the name of your session cookie (somehow obvious, let it be called "_session
"), you can simply receive the data in it by:
cookies.encrypted['_session']
So, you should be able to do something like:
user_id = cookies.encrypted['_session']['user_id']
This depends on do you use cookie store for the session and on the exact authentication approach, but in any case the data you need should be there.
I found this approach more convenient as the session is already managed by the authentication solution you use and you more likely don't need to care about things like cookie expiration and duplication of the authentication logic.
Here is more complete example:
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
session = cookies.encrypted['_session']
user_id = session['user_id'] if session.present?
self.current_user = (user_id.present? && User.find_by(id: user_id))
reject_unauthorized_connection unless current_user
end
end
end
来源:https://stackoverflow.com/questions/42451889/how-do-i-get-current-user-in-actioncable-rails-5-api-app