Switch authentication modules for each controller action

I have a Rails site that uses Devise for authentication. I have one page ( PhotosController#create ) that should authenticate users without cookies. I do this with a module :token_authenticatable Devise, which authenticates the user if the supplied token matches the token stored on the server side. (See this SO question if you're interested.)

This is a good policy to expire or change a token after the action expires. This does not allow an attacker to sniff a token and use it for successful authentication as a user. However, in my case, I cannot finish or change the token, because the client client on the client side uploads several photos, each of which leads to a separate POST on PhotosController#create . Therefore, if I expire the token after successful creation, the second, third, etc. Download will fail.

Development modules are defined at the model level (for example, the User model). I need more detail than this.

My question is: how to enable the module :token_authenticatable for only one action of one controller? Or, what is the same as disabling a module :token_authenticatable for all controllers and actions except for one action?

+3
source share
4 answers

As a developer of one development plugin (devise_rpx_connectable), I will be happy to answer your question.

TokenAuthenticatable is one Devise strategy, you can read its code here:

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

As you can see, every development strategy has power? and / or valid_request? a method that is called to determine if the strategy should be enabled. So you can easily override this strategy for your needs or can you also override valid_request? method. Just load this type of code into the initializer (AFTER the program is loaded, of course):

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

I have not tested this, I don’t know if it works out of the box, but I hope you understand it, if it doesn’t work, use a debugger or create your own development strategy (see my plugin, it's easy to understand), etc. .

In addition, when you use this strategy, the user will be saved in the session if you do not use the stateless_token parameter, see https://github.com/plataformatec/devise/blob/master/lib/devise/models/token_authenticatable.rb# L27

+7
source

Put this in the initializer

 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
source

The slainer68 approach is good, but it does not work for me as it is, so I will add my possible solution here.

In config/initializers/devise.rb , which already had a Devise.setup do |config| ... end block Devise.setup do |config| ... end Devise.setup do |config| ... end , I added the following:

 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 

I also added this to the Devise.setup block:

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

It would be better to simply update the existing strategy :token_authenticatable , but it was not loaded into Warden by the time this code was executed. As a result of using a strategy with a different name, I had to duplicate some of the methods and methods of the class from Devise::Strategies::TokenAuthenticatable , including:

  • 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)

I also had to remove: token_authenticatable from the devise line at the top of the user model.

I also made a slainer68 decision and added :stateless_token => false to the devise_for parameters in config/routes.rb .

+1
source

The simplest solution can be found here: Indicate allow authentication token with the action of one controller I apologize, but I do not know how to mark the issue as a possible repetition, etc. The indicated solution worked for me using rails 3.2.7.

So it does not use def valid_request? which is private and cannot be called directly from the class outside. (check the base code of the strategy https://github.com/plataformatec/devise/blob/master/lib/devise/strategies/authenticatable.rb#L15 ). Therefore, not quite the best place to redefine. You should use valid? instead valid? and have something like this:

 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 
+1
source

Source: https://habr.com/ru/post/1336191/


All Articles