在ApplicationController中设计current_user nil,但不在另一个控制器中设置(使用简单令牌认证)

时间:2015-11-13 22:18:27

标签: ruby-on-rails ruby-on-rails-3 authentication devise

我有一个Rails 3.2.22应用程序在生产中运行1年,它使用Devise来验证用户。

我正在尝试实施令牌身份验证,因此我可以使用名为简单令牌身份验证的Gem https://github.com/gonzalo-bulnes/simple_token_authentication

发送带有URL params的事务电子邮件,该URL params可以自动登录用户

按照所有说明操作后,我用before_filter :authenticate_user!替换了控制器中的acts_as_token_authentication_handler_for User

gem与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问题。

1 个答案:

答案 0 :(得分:0)

当您在acts_as_token_authentication_handler_for中调用DashboardController指令时,它会为控制器声明一些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)调用acts_as_token_authentication_handler_for中的ApplicationControoler指令,并以某种方式跳过不需要它的控制器。 (我不喜欢这样,但如果第一个不起作用,它可能会有所帮助。)

3)将populate_last_contacts_for_menu过滤器逻辑移动到帮助器中。我认为这是最好的解决方案。该逻辑不属于控制器。当请求不是“获取”时,此过滤器不执行任何操作,因为在这种情况下您不需要呈现视图。

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 %>