-
Notifications
You must be signed in to change notification settings - Fork 5.5k
per-Controller auth strategies #5392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
per-Controller auth strategies #5392
Conversation
- It says that the option is added to devise_for, but it is actually added to the devise method in the model.
…odules Fix comment in some modules [ci skip]
Update a couple other modules that still referred to `devise_for` to point to `devise`, and make all of them more consistent. We can only mention `devise`, that should be clear enough about it being options for the model method.
…ence` (heartcombo#5357) Remove `ActiveSupport::Dependencies.reference` This was deleted from Rails: rails/rails@14d4edd As far as I can tell, it was meant to add a performance boost at some point in the past but doesn't seem to do anything useful these days.
…5397) Changes deprecated `ActiveSupport::Dependencies.constantize(model_name)` to `model_name.constantize` Co-authored-by: Carlos Antonio da Silva <carlosantoniodasilva@gmail.com>
It appears setting the `rack.session` to a simple hash doesn't work anymore as it now has a few additional methods Rails is relying on to determine whether it's enabled or not: rails/rails#42231 Failure: NoMethodError: undefined method `enabled?' for {}:Hash rails (f55cdafe4b82) actionpack/lib/action_dispatch/middleware/flash.rb:62:in `commit_flash' Turns we we don't seem to need to set `rack.session` for the tests here.
DEPRECATION WARNING: Using legacy connection handling is deprecated.
Please set `legacy_connection_handling` to `false` in your application.
Add Rails 7 / main support
Use `AS::Dependencies` as before if we still can, otherwise use the new direct `constantize` call for Rails 7+. Leave a TODO to help remind us this can be removed once we drop support to Rails versions prior to 7 in the future.
This commit adds support for latest Rails release.
Add support for Rails 7
Also note in the Changelog that Turbo is not fully supported yet.
|
I'd like to bump this PR. We have the same use case: API should only use token authentication, rest of the app tries all approaches. And I'd guess we're not be the only ones.. Anything speaking against integrating it into devise? Happy to help with the PR in case anything is still missing. |
|
We are using this branch in production so it's been really invaluable. |
lib/devise/controllers/helpers.rb
Outdated
| # self.strategies = [:authenticatable, :database_authenticatable] | ||
| # self.strategies = { user: :authenticatable, admin: :database_authenticatable } | ||
| # | ||
| class_attribute :strategies |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on making this a controller instance method as opposed to a class attribute? Agreed that this would be useful -- I'm in the middle of implementing something similar for a multi-tenant app with a single scope but a few separate auth mechanisms -- but I think it could be helpful to have the request context available if possible.
I realize Warden encourages you to locate strategy eligibility in the strategy itself, but if we did want to pick explicitly in the controller based on the request or some runtime information, that would be possible with an instance method but not a class attribute.
Making this an instance method would also make this function a little closer to the way the auth_options work in Devise::SessionsController#create.: https://github.com/heartcombo/devise/blob/main/app/controllers/devise/sessions_controller.rb#L47
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems perfectly reasonable. I'll take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed on your recommendation
lib/devise/controllers/helpers.rb
Outdated
| mappings.each do |mapping| | ||
| opts[:scope] = mapping | ||
| warden.authenticate!(opts) if !devise_controller? || opts.delete(:force) | ||
| warden.authenticate!(*self.class.strategies_for(mapping), opts) if !devise_controller? || opts.delete(:force) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll likely also want to respect any per-controller strategies here (and add self.class.strategies_for to this .authenticate call in Devise::SessionsController#create):
https://github.com/heartcombo/devise/blob/main/app/controllers/devise/sessions_controller.rb#L19
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that Devise::SessionsController probably doesn't include these controller helpers, but as part of this work, it may be worth considering how to allow custom strategies in that controller. (It would be a mildly more complete solution, even if it's just adding an empty auth_strategies or strategies method to that controller and respecting it in the authenticate call.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is now possible to override the SessionsController too :)
…ub.com:braindeaf/devise into RL_feature/configure_strategies_per_controller
|
Just for the record, another solution I've seen encouraged for this problem is to set something in the Rails/request env in the controller and check it in the Strategy. Ex: class Api::Users::SessionsController
prepend_before_action :skip_token_strategy!, only: :create
private def skip_token_strategy!
request.env['devise.skip_token_strategy'] = true
end
end
class Devise::Strategies::Token
def valid?
!env['devise.skip_token_strategy']
end
endNot suggesting anything one way or the other; just anticipating what other responses to this proposal might be. (Ex: "This can already be done, and strategy eligibility / validity should be determined in the Strategy itself.") |
|
Not sure how I feel about that solution. A Strategy should be able to understand what is valid or not sure. Say, if it's a JWT token request and maybe forcing the request to be JSON. That I could understand. But deciding on whether to force the request to be invalid for some other arbitrary reason seems unreasonable to inject a reason to cause the Strategy to fail, not to mention that it will run every Strategy which is unnecessary if you know you only want to run one of them. Not sure what the hell has happened after my merge of upstream, now I have 23 file changes :S |
which can be overriden
Adding BlahController.strategies config to allow only specific strategies to be run on a per-controller basis. The best example of this is we have at least 5 strategies for our User class, but when it comes to our API controllers we only want :jwt to run, ignoring database_authenticatable, yubi_key, etc.
This was my initial solution, before this pull request.
https://robl.me/posts/the-magical-devise-journey