How do I get current_user in ActionCable rails-5-api app?

匆匆过客 提交于 2019-11-29 17:22:49

问题


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 and cookies.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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!