mirror of
https://github.com/heartcombo/devise.git
synced 2022-11-09 12:18:31 -05:00
Extend params sanitizer, to make it easier to add/remove permitted params
- Move the default permitted parameters into ParameterSanitizer::PermittedParameters - Add devise_permitted_parameters helper - devise_permitted_parameters.add to add permitted parameters - devise_permitted_parameters.remove to remove Devise's defaults - devise_permitted_parameters.for to access the parameters for a given action - Update 'Strong Parameters' section of README Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
This commit is contained in:
parent
87edf0fbcf
commit
5e7caffc9e
4 changed files with 108 additions and 21 deletions
20
README.md
20
README.md
|
@ -187,7 +187,7 @@ There are just three actions in Devise that allows any set of parameters to be p
|
|||
* `sign_up` (`Devise::RegistrationsController#create`) - Permits authentication keys plus `password` and `password_confirmation`
|
||||
* `account_update` (`Devise::RegistrationsController#update`) - Permits authentication keys plus `password`, `password_confirmation` and `current_password`
|
||||
|
||||
In case you want to customize the permitted parameters (the lazy way™) you can do with a simple before filter in your `ApplicationController`:
|
||||
In case you want to permit additional parameters (the lazy way™) you can do with a simple before filter in your `ApplicationController`:
|
||||
|
||||
```ruby
|
||||
class ApplicationController < ActionController::Base
|
||||
|
@ -196,11 +196,27 @@ class ApplicationController < ActionController::Base
|
|||
protected
|
||||
|
||||
def configure_permitted_parameters
|
||||
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email) }
|
||||
# permit parameters for all actions
|
||||
devise_permitted_parameters.add(:username, :age)
|
||||
|
||||
# permit a parameter for a single action
|
||||
devise_permitted_parameters.for(:sign_up) << :hometown
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
To remove or overwrite the defaults that Devise provides:
|
||||
|
||||
```ruby
|
||||
def configure_permitted_parameters
|
||||
# remove a permitted parameter
|
||||
devise_permitted_parameters.remove(:email)
|
||||
|
||||
# overwrite the Devise defaults
|
||||
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email) }
|
||||
end
|
||||
```
|
||||
|
||||
If you have multiple Devise models, you may want to set up different parameter sanitizer per model. In this case, we recommend inheriting from `Devise::ParameterSanitizer` and add your own logic:
|
||||
|
||||
```ruby
|
||||
|
|
|
@ -91,6 +91,10 @@ module Devise
|
|||
end
|
||||
end
|
||||
|
||||
def devise_permitted_parameters
|
||||
devise_parameter_sanitizer.permitted_parameters
|
||||
end
|
||||
|
||||
# Tell warden that params authentication is allowed for that specific page.
|
||||
def allow_params_authentication!
|
||||
request.env["devise.allow_params_authentication"] = true
|
||||
|
|
|
@ -30,34 +30,61 @@ module Devise
|
|||
end
|
||||
|
||||
class ParameterSanitizer < BaseSanitizer
|
||||
|
||||
class PermittedParameters
|
||||
|
||||
def initialize(resource_class)
|
||||
@resource_class = resource_class
|
||||
@for = { :sign_in => sign_in, :sign_up => sign_up, :account_update => account_update }
|
||||
end
|
||||
|
||||
def sign_in
|
||||
auth_keys + [:password, :remember_me]
|
||||
end
|
||||
|
||||
def sign_up
|
||||
auth_keys + [:password, :password_confirmation]
|
||||
end
|
||||
|
||||
def account_update
|
||||
auth_keys + [:password, :password_confirmation, :current_password]
|
||||
end
|
||||
|
||||
def auth_keys
|
||||
@resource_class.authentication_keys.respond_to?(:keys) ? @resource_class.authentication_keys.keys : @resource_class.authentication_keys
|
||||
end
|
||||
|
||||
def for(kind)
|
||||
@for[kind]
|
||||
end
|
||||
|
||||
def add(*params)
|
||||
@for.each { |action, permitted| permitted.push *params }
|
||||
end
|
||||
|
||||
def remove(*params)
|
||||
@for.each do |action, permitted|
|
||||
permitted.delete_if { |param| params.include? param }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def permitted_parameters
|
||||
@permitted_parameters ||= PermittedParameters.new(@resource_class)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fallback_for(kind)
|
||||
if respond_to?(kind, true)
|
||||
send(kind)
|
||||
elsif (permitted = permitted_parameters.for(kind))
|
||||
default_params.permit permitted
|
||||
else
|
||||
raise NotImplementedError, "Devise Parameter Sanitizer doesn't know how to sanitize parameters for #{kind}"
|
||||
end
|
||||
end
|
||||
|
||||
# These are the params used to sign in a user so we don't need to
|
||||
# mass-assign the password param in order to authenticate. Excluding it
|
||||
# here allows us to construct a new user without sensitive information if
|
||||
# authentication fails.
|
||||
def sign_in
|
||||
default_params.permit(*auth_keys + [:password, :remember_me])
|
||||
end
|
||||
|
||||
def sign_up
|
||||
default_params.permit(*(auth_keys + [:password, :password_confirmation]))
|
||||
end
|
||||
|
||||
def account_update
|
||||
default_params.permit(*(auth_keys + [:password, :password_confirmation, :current_password]))
|
||||
end
|
||||
|
||||
def auth_keys
|
||||
resource_class.authentication_keys.respond_to?(:keys) ? resource_class.authentication_keys.keys : resource_class.authentication_keys
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,6 +48,46 @@ if defined?(ActionController::StrongParameters)
|
|||
assert_equal({ "email" => "jose", "password" => "invalid" }, sanitizer.for(:sign_in))
|
||||
end
|
||||
|
||||
test 'adding permitted parameters for a single action' do
|
||||
sanitizer = sanitizer(user: { "email" => "jose", "username" => "jose1" })
|
||||
sanitizer.permitted_parameters.for(:sign_up).push(:username)
|
||||
|
||||
assert_equal({ "email" => "jose", "username" => "jose1" }, sanitizer.for(:sign_up))
|
||||
assert_equal({ "email" => "jose" }, sanitizer.for(:sign_in))
|
||||
end
|
||||
|
||||
test 'adding permitted parameters for all actions' do
|
||||
sanitizer = sanitizer(user: { "email" => "jose", "username" => "jose1" })
|
||||
sanitizer.permitted_parameters.add(:username)
|
||||
|
||||
assert_equal({ "email" => "jose", "username" => "jose1" }, sanitizer.for(:sign_in))
|
||||
assert_equal({ "email" => "jose", "username" => "jose1" }, sanitizer.for(:sign_up))
|
||||
assert_equal({ "email" => "jose", "username" => "jose1" }, sanitizer.for(:account_update))
|
||||
end
|
||||
|
||||
test 'removing default parameters' do
|
||||
sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
|
||||
sanitizer.permitted_parameters.remove(:email)
|
||||
|
||||
assert_equal({ "password" => "invalid" }, sanitizer.for(:sign_in))
|
||||
assert_equal({ "password" => "invalid" }, sanitizer.for(:sign_up))
|
||||
assert_equal({ "password" => "invalid" }, sanitizer.for(:account_update))
|
||||
end
|
||||
|
||||
test 'adding multiple permitted parameters' do
|
||||
sanitizer = sanitizer(user: { "email" => "jose", "username" => "jose1", "role" => "valid" })
|
||||
|
||||
sanitizer.permitted_parameters.add(:username, :role)
|
||||
assert_equal({ "email" => "jose", "username" => "jose1", "role" => "valid" }, sanitizer.for(:sign_in))
|
||||
end
|
||||
|
||||
test 'removing multiple default parameters' do
|
||||
sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid", "remember_me" => "1" })
|
||||
sanitizer.permitted_parameters.remove(:email, :password)
|
||||
|
||||
assert_equal({ "remember_me" => "1" }, sanitizer.for(:sign_in))
|
||||
end
|
||||
|
||||
test 'raises on unknown hooks' do
|
||||
sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
|
||||
assert_raise NotImplementedError do
|
||||
|
|
Loading…
Add table
Reference in a new issue