最近我正在从事一个项目,其中我使用 Devise 来保存不同服务的用户令牌。情况有点不同,但你的问题仍然让我思考了一段时间。
我会将 Devise 绑定到Account无论如何模型。为什么?让我们来看看。
由于我的电子邮件是唯一可以识别我作为用户的信息(并且您指的是Account作为用户)我会把它放在accounts
表与密码配对,以便我最初能够使用基本的电子邮件/密码身份验证。我还将 API 令牌保留在authentications
.
正如您所提到的,OmniAuth 模块需要存储提供商和 ID。如果您希望您的用户能够同时连接不同的服务(并且出于某种原因你这样做)那么显然您需要将两个提供者 ID 对保存在某处,否则每次单个用户进行身份验证时都会简单地覆盖一对。这引导我们到验证模型已经适合该模型并且可以参考Account.
因此,当您寻找提供商 ID 对时,您需要检查authentications
表而不accounts
。如果找到,您只需返回一个account
与之相关。如果没有,则检查包含此类电子邮件的帐户是否存在。创建新的authentication
如果答案是肯定的,否则创建一个然后创建authentication
for it.
更具体:
#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
这应该可以满足您的需要,同时保持您想要的灵活性。