Пользовательский сеанс#создание параметров
Чтобы интегрировать мой веб-сайт с веб-сайтом партнера, мне нужно иметь имена пользовательских параметров:
По умолчанию параметры devise sessions#create следующие:
user[email]
и user[password]
(Эти параметры преобразуются во вложенный Хэш в: user)
Для моего партнера, я должен быть в состоянии ответить на
email
и password
Я прошел через множество попыток, и я закончил реализовывать обычай Devise::Strategy
и обычай user#find_for_database_authentication
, чтобы иметь возможность поймать их параметры.
Разработать:: Стратегии:: CustomSso.rb
require 'devise/strategies/database_authenticatable'
module Devise
module Strategies
class CustomSso < DatabaseAuthenticatable
def valid?
params[:sso]=="true"
end
def authenticate!
password = params[:password]
resource = password.present? && mapping.to.find_for_database_authentication(params)
hashed = false
if validate(resource){ hashed = true; resource.valid_password?(password) }
remember_me(resource)
resource.after_database_authentication
success!(resource)
end
mapping.to.new.password = password if !hashed && Devise.paranoid
fail(:not_found_in_database) unless resource
end
end
end
end
Пользователь.rb
class User < ActiveRecord::Base
....
def self.find_for_database_authentication(params)
User.find_by(email: "#{params[:email]}")
end
....
end
Это работает, но есть ли лучший или более простой способ сделать это ?1 ответ:
Причина
Причина, по которой аутентификация происходит против "исходных" параметров, не в том, что
ApplicationController
before_action
обратный вызов выполняется поздно или запрос модифицируется (восстанавливается) позже, но потому, чтоdevise
принимает параметры не от объекта params контроллера.Первоначально в Warden params будут взяты из новых
Rack::Request
, создано из env (environment) значение:# Convenience method to access the rack request. # :api: public def request @request ||= Rack::Request.new(@env) end # request
В
Devise
, однако, он исправлен на новый экземплярActionDispatch::Request
вместо этого, так вот почему меняется запрос в маршрутах.РБ (см. Варианты ниже) будет работать.module Warden::Mixins::Common def request @request ||= ActionDispatch::Request.new(env) end
Фактически, использование запроса ActionDispatch позволяет фактически изменять параметры запроса перед обработкой Devise, см. Решение 4 ниже.
Затем
params
берутся из этого запроса (код от Warden Base mixin) для дальнейшего извлечения значений для аутентификации:# Convenience method to access the rack request params # :api: public def params request.params end # params
Аутентифицируемая стратегия Devise имеет
params_auth_hash
помощника для извлечения только необходимых параметров из всех (область действия - ~ имя модели, например, пользователь)# Extract the appropriate subhash for authentication from params. def params_auth_hash params[scope] end
Хотя вы можете настроить имена ключей, которые будут взяты из
params_auth_hash
В вашей модели на основе Devise, вы не можете настроить, чтобы не "вырезать" только[scope]
часть params# * +authentication_keys+: parameters used for authentication. By default [:email].
Решения
Поэтому есть несколько вариантов:
1) переопределение параметров метод (общественный инспектор общего миксин, не параметры способ запроса или контроллера!) в вашей стратегии для "заплатки" параметров нет, например
class CustomSso < DatabaseAuthenticatable def params request.params[:user][:email] = request.params[:email] request.params end
2) перепишите метод params_auth_hash (private in
authenticatable
strategy by Devise) в том же месте:def params_auth_hash params[scope][:email] = params[:email] params[scope] # just return full params and not [scope] here in your case? end
3) Изменение параметров запроса в маршрутах
Грязный хак путем изменения параметров запроса в пользовательском ограничении rails route (
config/routes.rb
). Добавить следующее передdevise_for :<model_name>
post '/users/sign_in', constraints: lambda { |request| if URL_IS_FOR_SSO? && request.params[:password] && request.params[:email] request.params[:user] = {password: request.params[:password], email: request.params[:email]} end false #doesn't apply this route, proceed to further routing }
4) (лучше всего, если работает) Изменение параметров запроса в контроллере приложения
before_action
Вы также можете изменить имя параметров передан в запросе, чтобы удовлетворить разработать конвенцию, а затем использовать по умолчанию разработать стратегию. Вы можете использовать какой-то метод перезаписи, самый простой-поместить фильтр внутрь
ApplicationController
.важно - как источник путаницы,
params
метод ActionController имеет отношение к StrongParamaters понятие и совершенно отличное от запроса.параметры (которые в основном только хэш).class ApplicationController < ActionController::Base ... before_action :rewrite_param_names private # !! important - use request.params and not just params!! def rewrite_param_names if URL_IS_FOR_SSO? && request.params[:password] && request.params[:email] request.params[:user] = {password: request.params[:password], email: request.params[:email]} end end end
Это работает, потому что ActionDispatch:: Request store ссылается на параметры хэшируются в заголовке env и позволяют обновить этот хэш. Источник :
# Returns both GET and POST \parameters in a single hash. def parameters params = get_header("action_dispatch.request.parameters") return params if params ... set_header("action_dispatch.request.parameters", params) params end
Чтобы сделать before_action более сфокусированным, вы можете создать пользовательский контроллер для Devise и установить его в parent_controller setting for Devise
# The parent controller all Devise controllers inherits from. # Defaults to ApplicationController. This should be set early # in the initialization process and should be set to a string. mattr_accessor :parent_controller @@parent_controller = "ApplicationController"