Pracowałem ostatnio nad projektem, w którym korzystałem z Devise, aby zachować tokeny użytkownika dla różnych usług. Nieco inny przypadek, ale wciąż twoje pytanie mnie zastanowiło.
Wezwę Devise do Konto model mimo to. Czemu? Zobaczmy.
Ponieważ mój e-mail jest jedyną rzeczą, która może identyfikować się jako użytkownik (i odnoszą się do konta jak Użytkownika) Chciałbym umieścić go w accounts
stole w parze z hasłem tak, że jestem w stanie początkowo korzystać z podstawowego uwierzytelniania za pomocą poczty e-mail/hasła. Również będę przechowywać tokeny API w authentications
.
Jak już wspomniano, moduł OmniAuth musi przechowywać dostawcę i identyfikator. Jeśli chcesz, aby Twój użytkownik mógł łączyć się z różnymi usługami w tym samym czasie, (i z jakiegoś powodu), to oczywiście musisz zachować obie pary identyfikatorów dostawcy, w przeciwnym razie po prostu zostanie nadpisany za każdym razem, gdy pojedynczy użytkownik uwierzytelnia się.To prowadzi nas do modelu Authentication, który jest już odpowiedni do tego i ma odniesienie do Konta.
Szukając pary usługodawców, należy sprawdzić tabelę authentications
, a nie accounts
. Jeśli zostanie znaleziony, po prostu zwrócisz skojarzony z nim account
. Jeśli nie, sprawdź, czy istnieje konto zawierające taki e-mail. Utwórz nową authentication
, jeśli odpowiedź brzmi "tak", w przeciwnym razie utwórz ją, a następnie utwórz dla niej authentication
.
Aby być bardziej konkretne:
#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
To powinno dać ci to, czego potrzebujesz, zachowując elastyczność chcesz.
Dzięki za odpowiedź! Zastanawiam się tylko nad tokenem; czy token nie powinien znajdować się również na koncie? Prawdopodobnie wykorzystam strategię TokenAuthenticatable z narzędziem i jest ona zwykle używana w rzeczywistym modelu użytkownika/konta? Czy możliwe jest użycie domyślnych strategii w modelu użytkownika/konta, ale TokenAuthenticatable w oddzielnym modelu, takim jak uwierzytelnianie? – thejaz
Nie jestem pewien, czy to możliwe, ale możesz zawsze zastąpić metody z DeviseSessionsController. Po prostu osobiście używałbym 'omniautowalnego'. – shrimpsushi