如何在 ActionCable rails-5-api 应用程序中获取 current_user?
How do I get current_user in ActionCable rails-5-api app?
为什么我无法在我的频道内检索 current_user
或者我应该如何检索 current_user
?
我用什么?
- Rails 5.0.1 --api (我没有任何观点也没有喝咖啡)
- 我使用 react-native 应用程序来测试这个 (在没有授权的情况下工作正常)
- 我不使用设计进行身份验证(我使用 JWT 而不是使用 Knock,所以没有 cookie)
正按照 rubydoc.info
中的描述尝试将 current_user
放入我的 ActionCable 频道
代码看起来像
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
和运行它,我得到这个错误:
[NoMethodError - undefined method `identified_by' for MessageChannel:Class]
如果我删除 identified_by :current_user
,我会得到
[NameError - undefined local variable or method `current_user' for #<MessageChannel:0x7ace398>]
如果您看到您提供的文档,您就会知道 identified_by
不是 Channel
实例的方法。这是 Actioncable::Connection
的方法。
来自 Rails Actioncable 概述指南,这是 Connection
class 的样子:
#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
如您所见,current_user
在这里不可用。相反,您必须在此处创建一个 current_user
连接。
websocket 服务器没有会话,但它可以读取与主应用程序相同的 cookie。所以我想,你需要在验证后保存cookie。
如果您在 rails 中使用 devise gems,请替换此函数:
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
希望对您有所帮助。
嗯,理论上:
- 您可以访问
ActiveCable::Connection
class 中的 cookie。
- 您可以设置和接收
cookies.signed
和cookies.encrypted
- 应用程序和 ActionCable 共享相同的配置,因此它们共享相同的`secret_key_base'
因此,如果您知道会话 cookie 的名称(很明显,就叫它“_session
”),您可以通过以下方式简单地接收其中的数据:
cookies.encrypted['_session']
因此,您应该可以执行以下操作:
user_id = cookies.encrypted['_session']['user_id']
这取决于您是否为会话使用 cookie 存储以及确切的身份验证方法,但无论如何您需要的数据都应该存在。
我发现这种方法更方便,因为会话已经由您使用的身份验证解决方案管理,您很可能不需要关心 cookie 过期和身份验证逻辑重复等问题。
这里是更完整的例子:
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
对于Rails5API模式:
application_controller.rb
class ApplicationController < ActionController::API
include ActionController::Cookies
...
token = request.headers["Authorization"].to_s
user = User.find_by(authentication_token: token)
cookies.signed[:user_id] = user.try(:id)
connection.rb
class Connection < ActionCable::Connection::Base
include ActionController::Cookies
...
if cookies.signed[:user_id] && current_user = User.where(id: cookies.signed[:user_id]).last
current_user
else
reject_unauthorized_connection
end
config/application.rb
config.middleware.use ActionDispatch::Cookies
在 ApplicationCable::Connection
中设置 self.current_user
后,它在频道实例中可用。
所以你可以像 Sajan 写的那样设置你的身份验证,只需在 MessageChannel
中使用 current_user
例如,这段代码对我有用
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :verified_user
def connect
self.verified_user = find_verified_user
end
private
def current_user
jwt = cookies.signed[:jwt]
return unless jwt
decoded = JwtDecodingService.new(jwt).decrypt!
@current_user ||= User.find(decoded['sub']['user_id'])
end
def find_verified_user
current_user || reject_unauthorized_connection
end
end
end
class NextFeaturedPlaylistChannel < ApplicationCable::Channel
def subscribed
stream_from "next_featured_playlist_#{verified_user.id}"
end
end
为什么我无法在我的频道内检索 current_user
或者我应该如何检索 current_user
?
我用什么?
- Rails 5.0.1 --api (我没有任何观点也没有喝咖啡)
- 我使用 react-native 应用程序来测试这个 (在没有授权的情况下工作正常)
- 我不使用设计进行身份验证(我使用 JWT 而不是使用 Knock,所以没有 cookie)
正按照 rubydoc.info
中的描述尝试将current_user
放入我的 ActionCable 频道
代码看起来像
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
和运行它,我得到这个错误:
[NoMethodError - undefined method `identified_by' for MessageChannel:Class]
如果我删除 identified_by :current_user
,我会得到
[NameError - undefined local variable or method `current_user' for #<MessageChannel:0x7ace398>]
如果您看到您提供的文档,您就会知道 identified_by
不是 Channel
实例的方法。这是 Actioncable::Connection
的方法。
来自 Rails Actioncable 概述指南,这是 Connection
class 的样子:
#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
如您所见,current_user
在这里不可用。相反,您必须在此处创建一个 current_user
连接。
websocket 服务器没有会话,但它可以读取与主应用程序相同的 cookie。所以我想,你需要在验证后保存cookie。
如果您在 rails 中使用 devise gems,请替换此函数:
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
希望对您有所帮助。
嗯,理论上:
- 您可以访问
ActiveCable::Connection
class 中的 cookie。 - 您可以设置和接收
cookies.signed
和cookies.encrypted
- 应用程序和 ActionCable 共享相同的配置,因此它们共享相同的`secret_key_base'
因此,如果您知道会话 cookie 的名称(很明显,就叫它“_session
”),您可以通过以下方式简单地接收其中的数据:
cookies.encrypted['_session']
因此,您应该可以执行以下操作:
user_id = cookies.encrypted['_session']['user_id']
这取决于您是否为会话使用 cookie 存储以及确切的身份验证方法,但无论如何您需要的数据都应该存在。
我发现这种方法更方便,因为会话已经由您使用的身份验证解决方案管理,您很可能不需要关心 cookie 过期和身份验证逻辑重复等问题。
这里是更完整的例子:
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
对于Rails5API模式:
application_controller.rb
class ApplicationController < ActionController::API
include ActionController::Cookies
...
token = request.headers["Authorization"].to_s
user = User.find_by(authentication_token: token)
cookies.signed[:user_id] = user.try(:id)
connection.rb
class Connection < ActionCable::Connection::Base
include ActionController::Cookies
...
if cookies.signed[:user_id] && current_user = User.where(id: cookies.signed[:user_id]).last
current_user
else
reject_unauthorized_connection
end
config/application.rb
config.middleware.use ActionDispatch::Cookies
在 ApplicationCable::Connection
中设置 self.current_user
后,它在频道实例中可用。
所以你可以像 Sajan 写的那样设置你的身份验证,只需在 MessageChannel
current_user
例如,这段代码对我有用
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :verified_user
def connect
self.verified_user = find_verified_user
end
private
def current_user
jwt = cookies.signed[:jwt]
return unless jwt
decoded = JwtDecodingService.new(jwt).decrypt!
@current_user ||= User.find(decoded['sub']['user_id'])
end
def find_verified_user
current_user || reject_unauthorized_connection
end
end
end
class NextFeaturedPlaylistChannel < ApplicationCable::Channel
def subscribed
stream_from "next_featured_playlist_#{verified_user.id}"
end
end