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
不太熟悉,就先不用這種方法啦?。