Devise 的 current_user nil 在 ApplicationController 中但不在不同的控制器中(使用简单令牌身份验证)
Devise's current_user nil in ApplicationController but not in a different controller (using Simple Token Authentication)
我有一个 Rails 3.2.22 应用程序 运行 在生产中使用了 +1 年,它使用 Devise 对用户进行身份验证。
我正在尝试实施令牌身份验证,因此我可以使用 Gem 名为简单令牌身份验证 https://github.com/gonzalo-bulnes/simple_token_authentication
按照所有说明进行操作后,我将控制器中的 before_filter :authenticate_user!
替换为 acts_as_token_authentication_handler_for User
。
gem 与 Devise 集成并默认 回退到 Devise,因此不再需要在控制器中调用 devise;如果参数中缺少令牌(或错误),Devise 将接管。
在我的测试中,如果我将此行添加到 ApplicationController
,一切正常,我可以使用 gem 生成的 authentication_token=
秘密登录用户。
但是我不需要 auth
用于 ApplicationController,我需要它用于其他控制器(比如 DashboardController),url 是 /dashboard
如果我将 acts_as_token_authentication_handler_for User
放入该控制器(替换 Devise 的调用),我会遇到最奇怪的情况。
使用 binding.pry,我可以确认 current_user
在模板加载期间设置正确。
但是模板中有一点使用了@last_emails,这是在 ApplicationController
.
中的一个方法中定义的
使用 binding.pry,我可以确认 current_user
是 nil。
这是代码:
class DashboardController < ApplicationController
layout 'material'
acts_as_token_authentication_handler_for User
并且在 ApplicationController 中:
class ApplicationController < ActionController::Base
layout 'omega'
before_filter :populate_last_contacts_for_menu
private
def populate_last_contacts_for_menu
if current_user
@last_contacts = Contact.where("user_id" => current_user.id).where('blocked != ? or blocked is null', true).last(10).reverse
end
end
有趣的是:使用 binding.pry,就像我说的,我可以检查模板中是否定义了 current_user(这意味着 sign_in 是成功的)。它甚至在更好的错误控制台中定义。但是,如果我转到主页,我会看到该用户未登录...
为此我在网上找遍了:阅读 Gem 的 github 中的所有问题以及 SO 中关于 current_user 为零的所有帖子,但没有光一点。
我的 devise_for :users
不在 routes.rb 的任何范围内,正如我所说,我在整个应用程序中多次调用 current_user,这是我第一次调用Devise 的问题。
当您在 DashboardController
中调用 acts_as_token_authentication_handler_for
指令时,它会声明一些 before_filters
以便控制器对用户进行身份验证。
但问题是当你继承rails控制器时,首先执行父控制器的过滤器,然后执行子控制器的过滤器。
父控制器是ApplicationController
。在它的 populate_last_contacts_for_menu
过滤器被调用的那一刻,用户没有被认证,因为 acts_as_token_authentication_handler_for
指令给出的认证过滤器还没有被调用,它们是在子控制器中声明的。
可能的解决方案:
1) 尝试附加 populate_last_contacts_for_menu
过滤器:
append_before_filter :populate_last_contacts_for_menu
我不确定它是否适用于你的情况,但你可以尝试找出答案。
2) 在 ApplicationControoler
中调用 acts_as_token_authentication_handler_for
指令,并以某种方式为不需要它的控制器跳过它。 (我不喜欢这种方式,但如果第一种方式不起作用,它可能会有所帮助。)
3) 将 populate_last_contacts_for_menu
过滤器逻辑移动到助手中。我认为这是最好的解决方案。此逻辑不属于控制器。当请求不是 'get' 时,此过滤器不执行任何操作,因为在这种情况下您不需要呈现视图。
module ApplicationHelper
def last_contacts
@last_contacts ||= if signed_in?
Contact.where("user_id" => current_user.id).where('blocked != ? or blocked is null', true).last(10).reverse
else
[]
end
end
...
end
# View:
<% if last_contacts.present? %>
....
<% end %>
我有一个 Rails 3.2.22 应用程序 运行 在生产中使用了 +1 年,它使用 Devise 对用户进行身份验证。
我正在尝试实施令牌身份验证,因此我可以使用 Gem 名为简单令牌身份验证 https://github.com/gonzalo-bulnes/simple_token_authentication
按照所有说明进行操作后,我将控制器中的 before_filter :authenticate_user!
替换为 acts_as_token_authentication_handler_for User
。
gem 与 Devise 集成并默认 回退到 Devise,因此不再需要在控制器中调用 devise;如果参数中缺少令牌(或错误),Devise 将接管。
在我的测试中,如果我将此行添加到 ApplicationController
,一切正常,我可以使用 gem 生成的 authentication_token=
秘密登录用户。
但是我不需要 auth
用于 ApplicationController,我需要它用于其他控制器(比如 DashboardController),url 是 /dashboard
如果我将 acts_as_token_authentication_handler_for User
放入该控制器(替换 Devise 的调用),我会遇到最奇怪的情况。
使用 binding.pry,我可以确认 current_user
在模板加载期间设置正确。
但是模板中有一点使用了@last_emails,这是在 ApplicationController
.
使用 binding.pry,我可以确认 current_user
是 nil。
这是代码:
class DashboardController < ApplicationController
layout 'material'
acts_as_token_authentication_handler_for User
并且在 ApplicationController 中:
class ApplicationController < ActionController::Base
layout 'omega'
before_filter :populate_last_contacts_for_menu
private
def populate_last_contacts_for_menu
if current_user
@last_contacts = Contact.where("user_id" => current_user.id).where('blocked != ? or blocked is null', true).last(10).reverse
end
end
有趣的是:使用 binding.pry,就像我说的,我可以检查模板中是否定义了 current_user(这意味着 sign_in 是成功的)。它甚至在更好的错误控制台中定义。但是,如果我转到主页,我会看到该用户未登录...
为此我在网上找遍了:阅读 Gem 的 github 中的所有问题以及 SO 中关于 current_user 为零的所有帖子,但没有光一点。
我的 devise_for :users
不在 routes.rb 的任何范围内,正如我所说,我在整个应用程序中多次调用 current_user,这是我第一次调用Devise 的问题。
当您在 DashboardController
中调用 acts_as_token_authentication_handler_for
指令时,它会声明一些 before_filters
以便控制器对用户进行身份验证。
但问题是当你继承rails控制器时,首先执行父控制器的过滤器,然后执行子控制器的过滤器。
父控制器是ApplicationController
。在它的 populate_last_contacts_for_menu
过滤器被调用的那一刻,用户没有被认证,因为 acts_as_token_authentication_handler_for
指令给出的认证过滤器还没有被调用,它们是在子控制器中声明的。
可能的解决方案:
1) 尝试附加 populate_last_contacts_for_menu
过滤器:
append_before_filter :populate_last_contacts_for_menu
我不确定它是否适用于你的情况,但你可以尝试找出答案。
2) 在 ApplicationControoler
中调用 acts_as_token_authentication_handler_for
指令,并以某种方式为不需要它的控制器跳过它。 (我不喜欢这种方式,但如果第一种方式不起作用,它可能会有所帮助。)
3) 将 populate_last_contacts_for_menu
过滤器逻辑移动到助手中。我认为这是最好的解决方案。此逻辑不属于控制器。当请求不是 'get' 时,此过滤器不执行任何操作,因为在这种情况下您不需要呈现视图。
module ApplicationHelper
def last_contacts
@last_contacts ||= if signed_in?
Contact.where("user_id" => current_user.id).where('blocked != ? or blocked is null', true).last(10).reverse
else
[]
end
end
...
end
# View:
<% if last_contacts.present? %>
....
<% end %>