cbeer / devise-guests

fake 'em until you make 'em
MIT License
130 stars 31 forks source link

this wont work with typical action cable #47

Closed jtoy closed 10 months ago

jtoy commented 1 year ago

env['warden'].user is not set:

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    include SetCurrentRequestDetails

    identified_by :current_user, :current_account, :true_user
    impersonates :user

    delegate :params, :session, to: :request

    def connect
      self.current_user = find_verified_user
      set_request_details
      self.current_account = Current.account

      logger.add_tags "ActionCable", "User #{current_user.id}", "Account #{current_account.id}"
    end

    protected

    def find_verified_user

      if (current_user = env["warden"].user(:user))
        current_user
      else
        reject_unauthorized_connection
      end
    end

    def user_signed_in?
      !!current_user
    end

    # Used by set_request_details
    def set_current_tenant(account)
      ActsAsTenant.current_tenant = account
    end
  end
end
d3vkit commented 1 year ago

I was able to work around this by using a cookie:

class ApplicationController < ActionController::Base
  rescue_from StandardError, with: :full_backtrace

  before_action :set_user_id_cookie

  private

  def set_user_id_cookie
    cookies.signed["user.id"] = current_or_guest_user.id
  end
end

And this in 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
      logger.add_tags "ActionCable", current_user.name
    end

    protected

    def find_verified_user
      if (verified_user = User.find_by(id: cookies.signed["user.id"]))
        verified_user
      else
        reject_unauthorized_connection
      end
    end
  end
end
pacso commented 1 year ago

I used a similar approach.

In app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  before_action :set_action_cable_identifier

  private
    def set_action_cable_identifier
      cookies.encrypted[:guest_id] = guest_user.id unless current_user
    end
end

Then in app/channels/connection.rb

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user, :guest_user, :current_or_guest_user

    def connect
      unless (self.current_user = env["warden"].user)
        self.guest_user = User.find_by(id: cookies.encrypted[:guest_id], guest: true)
      end

      self.current_or_guest_user = self.current_user || self.guest_user
    end
  end
end
pacso commented 10 months ago

Closing this since there have been no further comments, and I can't reproduce any problem.

pacso commented 5 months ago

@jtoy - I have actually seen this issue now, but it's nothing to do with this gem. I assume you were trying to run your ActionCable server in a standalone configuration? Unfortunately, when you do that, you do not spin up the entire rails stack and consequently are missing the Warden middleware. As mentioned, you can work around it using encrypted cookies, providing you serve your cable requests from the same domain.