ActionCable中怎样使用devise进行验证

ActionCable是在rails中提供实时沟通的一个功能,与Laravel中的Broadcast功能类似。Devise则是一个非常著名的用于登录认证等内容的Gem。由于在ActionCable处理的过程中无法读取session的内容,但是能读取cookie的内容。所以本文介绍一下如何在ActionCable中处理devise的认证。

基本设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 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,具体如下

1
2
3
4
5
# 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文件的代码变成下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 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不太熟悉,就先不用这种方法啦😂。

参考资料