每个控制器操作切换Devise身份验证模块

时间:2010-11-04 15:58:19

标签: ruby-on-rails authentication devise

我有一个使用Devise进行身份验证的Rails站点。我有一个页面(PhotosController#create)需要在没有cookie的情况下对用户进行身份验证。我正在使用Devise的:token_authenticatable模块执行此操作,如果提供的令牌与存储在服务器端的令牌匹配,则会对用户进行身份验证。 (如果您感到好奇,请参阅this SO question。)

在操作完成后过期或更改令牌是一个很好的策略。这可以防止攻击者嗅探令牌并使用它成功地作为用户进行身份验证。但是,在我的情况下,我无法过期或更改令牌,因为客户端照片上传器上传了多张照片,每张照片都会导致单独的POST PhotosController#create。因此,如果我在成功创建后使令牌到期,则第二次,第三次等上传将失败。

设计模块在模型级别指定(例如User模型)。我需要更多的粒度。

我的问题是,如何为单个控制器的单个操作启用:token_authenticatable模块 ?或者,等效地,如何为一个操作禁用所有控制器的:token_authenticatable模块和之外的操作?

4 个答案:

答案 0 :(得分:7)

作为一个设计插件的开发者(devise_rpx_connectable),我很乐意回答你的问题。

TokenAuthenticatable是一个Devise策略,你可以在这里阅读它的代码:

https://github.com/plataformatec/devise/blob/master/lib/devise/strategies/token_authenticatable.rb

如您所见,每个设计策略都有效?和/或valid_request?调用的方法,用于确定是否应启用策略。因此,您可以根据需要轻松覆盖此策略,或者您也可以仅覆盖valid_request?方法。只需在初始化程序中加载这种代码(当然加载AFTER设计):

module Devise
  module Strategies
    class TokenAuthenticatable < Authenticatable
      private
      def valid_request?
        params[:controller] == "photos" && params[:action] == "create"
      end
    end
  end
end

我没有对此进行测试,我不知道这是否可以开箱即用,但我希望你看到这一点,如果不起作用,请使用调试器,或编写自己的设计策略(参见我的插件,很容易理解)等等。

此外,当您使用此策略时,除非您使用stateless_token选项,否则用户将存储在会话中,请参阅: https://github.com/plataformatec/devise/blob/master/lib/devise/models/token_authenticatable.rb#L27

答案 1 :(得分:2)

将其放入初始值设定项

require 'devise/strategies/base'
require 'devise/strategies/token_authenticatable'
module Devise
  module Strategies
    class TokenAuthenticatable < Authenticatable
      private
      def valid_request?
        params[:controller] == "photos" && params[:action] == "create"
      end
    end
  end
end

答案 2 :(得分:1)

slainer68的方法很好,但它对我不起作用,所以我会在这里添加我的最终解决方案。

在已config/initializers/devise.rb阻止Devise.setup do |config| ... end的{​​{1}}中,我预先添加了以下内容:

Warden::Strategies.add(:my_token_authenticatable, Devise::Strategies::TokenAuth
  def valid?
    mapping.to.respond_to?(:authenticate_with_token) && authentication_token(scope).present? && params[:controller] == 'photos' && params[:action] == 'create'
  end
end

我还将其添加到Devise.setup块:

config.warden do |manager|
  manager.default_strategies.unshift :my_token_authenticatable
end

最好只更新现有的:token_authenticatable策略,但是在执行此代码时尚未加载到Warden中。由于必须使用具有不同名称的策略,我不得不复制Devise::Strategies::TokenAuthenticatable中的一些方法和类方法,包括:

  • reset_authentication_token
  • reset_authentication_token!
  • self.authenticate_with_token(attributes)
  • self.token_authentication_key
  • valid_authentication_token?(incoming_auth_token)
  • self.find_for_token_authentication(token)

我还必须从User模型顶部的devise行中删除:token_authenticatable。

我也接受了slainer68的建议,并将:stateless_token => false添加到devise_forconfig/routes.rb的选项中。

答案 3 :(得分:1)

最简单的解决方案可以在这里找到:Devise allow token authentication on single controller action我很抱歉,但我不知道如何将问题标记为可能的重复,等等。上述解决方案适用于我使用rails 3.2.7。

总之,它不使用私有的def valid_request?,不能直接从外面的类调用。 (检查https://github.com/plataformatec/devise/blob/master/lib/devise/strategies/authenticatable.rb#L15处策略的基本代码)因此,不是完全覆盖的最佳位置。相反,您应该使用valid?并使用类似的内容:

require 'devise/strategies/base'
require 'devise/strategies/token_authenticatable'
module Devise
  module Strategies
    class TokenAuthenticatable < Authenticatable
      def valid?
        super && params[:controller] == "your controller" && params[:action] == "your action"
      end
    end
  end
end