Ответ 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
Это должно дать вам то, что вам нужно, сохраняя при этом гибкость.