1
0
Fork 0
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:
Alex Peattie 2013-08-11 19:47:18 +01:00 committed by José Valim
parent 87edf0fbcf
commit 5e7caffc9e
4 changed files with 108 additions and 21 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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