ActionCable 中怎樣使用 devise 進行驗證

Epona發表於2019-09-20

ActionCable是在rails中提供實時溝通的一個功能,與Laravel中的Broadcast功能類似。Devise則是一個非常著名的用於登入認證等內容的Gem。由於在ActionCable處理的過程中無法讀取session的內容,但是能讀取cookie的內容。所以本文介紹一下如何在ActionCable中處理devise的認證。

基本設定

# 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 verified_user = User.find_by(id: cookies.encrypted[:user_id])
          verified_user
        else
          reject_unauthorized_connection
        end
      end
  end
end

這是在Rails的官方文件中為我們提供的基本配置,但是由於devise在處理登入的時候並沒有為我們儲存對應的cookie。那麼我們應該怎麼辦呢?

設定Hook

我們可以通過設定Hook來讓使用者登入之後自動為我們設定cookie,具體如下

# app/config/initializers/warden_hooks.rb
Warden::Manager.after_set_user do |user,auth,opts|
  scope = opts[:scope]
  auth.cookies.signed["#{scope}.id"] = user.id
end

同時app/channels/application_cable/connection.rb檔案的程式碼變成下面這樣

# 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

這樣我們就可以完成基礎認證啦!

另一種方法

經過一些搜尋,我發現了可以使用另一種方法來實現認證,同時也不需要設定hook:

# 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 = env['warden'].user
          verified_user
        else
          reject_unauthorized_connection
        end
      end
  end
end

不過,由於我對env['warden'].user不太熟悉,就先不用這種方法啦?。

參考資料

There's nothing wrong with having a little fun.

相關文章