Подтвердить что ты не робот

Используйте отдельную модель проверки подлинности с помощью Devise on Rails

У меня есть простое решение, которое я сделал со следующими объектами:

  • Аккаунт (имеет поле токена, которое возвращается при аутентификации и использования в вызовах API)
  • Аутентификация (имеет auth_type/auth_id и ссылку на учетную запись)

У меня есть отдельная Аутентификация, чтобы иметь возможность подключать несколько способов входа (UUID устройства, адрес электронной почты/пароль, твиттер, facebook и т.д.). Но кажется, что во всех примерах Devise вы используете его на модели Пользователь (Аккаунт).

Разве это не так гибко? Например, модуль OmniAuth хранит поставщика и идентификатор в модели Пользователь, что произойдет, если вы хотите, чтобы вы могли войти в систему как из Twitter, так и из Facebook, есть только место для одного провайдера?

Должен ли я использовать Devise для моей модели Account или модели Аутентификация?

4b9b3361

Ответ 1

Недавно мы работали над проектом, в котором я использовал Devise для хранения токенов пользователей для разных сервисов. Немного другой случай, но все же ваш вопрос заставил меня задуматься.

Я бы привязал Devise к учетной записи. Зачем? Посмотрим.

Поскольку мое электронное письмо - это единственное, что может идентифицировать меня как пользователя (и вы ссылаетесь на Аккаунт как пользователь), я бы разместил его в таблице accounts в паре с паролем, поэтому что я изначально могу использовать базовую аутентификацию по электронной почте/паролю. Также я бы сохранил маркеры API в authentications.

Как вы уже упоминали, модуль OmniAuth должен хранить поставщика и идентификатор. Если вы хотите, чтобы ваш пользователь мог одновременно подключаться к разным службам (и по какой-то причине вы это делаете), то, очевидно, вам нужно где-то держать пары идентификаторов провайдера, иначе они будут просто перезаписаны каждый раз, когда один пользователь проверяет подлинность. Это приводит нас к модели Аутентификация, которая уже подходит для этого и имеет ссылку на Аккаунт.

Поэтому при поиске пары идентификатор провайдера вы хотите проверить таблицу authentications, а не accounts. Если он найден, вы просто возвращаете связанный с ним account. Если нет, вы проверяете, существует ли учетная запись, содержащая такое письмо. Создайте новый authentication, если ответ да, в противном случае создайте его, а затем создайте для него authentication.

Более конкретно:

#callbacks_controller.rb
controller Callbacks < Devise::OmniauthCallbacksContoller
  def omniauth_callback
    auth = request.env['omniauth.auth']
    authentication =  Authentication.where(provider: auth.prodiver, uid: auth.uid).first
    if authentication
      @account = authentication.account
    else
      @account = Account.where(email: auth.info.email).first
      if @account
        @account.authentication.create(provider: auth.provider, uid: auth.uid,
         token: auth.credentials[:token], secret: auth.credentials[:secret])
      else
        @account = Account.create(email: auth.info.email, password: Devise.friendly_token[0,20])
        @account.authentication.create(provider: auth.provider, uid: auth.uid,
         token: auth.credentials[:token], secret: auth.credentials[:secret])
      end
    end
    sign_in_and_redirect @account, :event => :authentication
  end
end

#authentication.rb
class Authentication < ActiveRecord::Base
  attr_accessible :provider, :uid, :token, :secret, :account_id
  belongs_to :account
end

#account.rb
class Account < ActiveRecord::Base
  devise :database_authenticatable
  attr_accessible :email, :password
  has_many :authentications
end

#routes.rb
devise_for :accounts, controllers: { omniauth_callbacks: 'callbacks' }
devise_scope :accounts do
  get 'auth/:provider/callback' => 'callbacks#omniauth_callback'
end

Это должно дать вам то, что вам нужно, сохраняя при этом гибкость.

Ответ 2

Вы можете разделить всю общую логику на модуль и использовать только ту же таблицу.

module UserMethods
  #...
end

class User < ActiveRecord::Base
  include UserMethods
  devise ...

end  

class Admin < ActiveRecord::Base
  include UserMethods
  self.table_name = "users"
  devise ...
end

И сконфигурируйте всю модель разработки отдельно в маршрутах, представлениях (при необходимости см. Конфигурирование представлений). В этом случае вы можете легко обрабатывать всю логику.

Также обратите внимание, что если вы считаете, что разработка предназначена только для модели пользователя, значит, вы ошибаетесь.

Например, - rails g devise Admin

Это создаст устройство для модели администратора.

Подробнее здесь.