每个控制器操作切换Devise身份validation模块
我有一个使用Devise进行身份validation的Rails站点。 我有一个页面( PhotosController#create
)需要在没有cookie的情况下对用户进行身份validation。 我正在使用Devise的:token_authenticatable
模块执行此操作,如果提供的令牌与存储在服务器端的令牌匹配,则会对用户进行身份validation。 (如果你很好奇,请参阅这个问题 。)
在操作完成后过期或更改令牌是一个很好的策略。 这可以防止攻击者嗅探令牌并使用它成功地作为用户进行身份validation。 但是,在我的情况下,我无法过期或更改令牌,因为客户端照片上传器上传了多张照片,每张照片都会导致一个单独的POST到PhotosController#create
。 因此,如果我在成功创建后使令牌到期,则第二次,第三次等上传将失败。
设计模块在模型级别指定(例如User
模型)。 我需要更多的粒度。
我的问题是,如何仅针对单个控制器的单个操作启用:token_authenticatable
模块? 或者,等效地,如何为除一个操作之外的所有控制器和操作禁用:token_authenticatable
模块?
作为一个设计插件的开发者(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
我没有测试过这个,我不知道是否可以开箱即用,但我希望你能看到重点,如果不起作用,请使用调试器,或编写自己的Devise策略(参见我的插件,它是容易理解)等
此外,当您使用此策略时,除非您使用stateless_token选项,否则用户将存储在会话中,请参阅: https : //github.com/plataformatec/devise/blob/master/lib/devise/models/token_authenticatable.rb# L27
把它放在初始化器中
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
slainer68的方法很好,但它对我不起作用,所以我将在这里添加我的最终解决方案。
在config/initializers/devise.rb
,已经有一个Devise.setup do |config| ... end
Devise.setup do |config| ... end
块,我在前面加上以下内容:
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的建议,并在config/routes.rb
添加了:stateless_token => false
到devise_for
的选项。
最简单的解决方案可以在这里找到: 设计允许在单个控制器操作上进行令牌认证我很抱歉,但我不知道如何将问题标记为可能的重复,等等。所提到的解决方案对我使用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