Пользовательский сеанс#создание параметров


Чтобы интегрировать мой веб-сайт с веб-сайтом партнера, мне нужно иметь имена пользовательских параметров:

По умолчанию параметры 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 2

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"