使用与Devise on Rails分开的身份验证模型

the*_*jaz 11 ruby ruby-on-rails devise omniauth ruby-on-rails-3

我有一个简单的解决方案,我已经使用以下对象:

  • 帐户(具有令牌字段,在API调用中进行身份验证和使用时返回)
  • 身份验证(具有auth_type/auth_id和对帐户的引用)

我有一个单独的身份验证模型,可以连接多种登录方式(设备UUID,电子邮件/密码,Twitter,Facebook等).但似乎在Devise的所有示例中,您都在用户(帐户)模型上使用它.

这不是那么灵活吗?例如,OmniAuth模块在User模型上存储提供者和ID ,如果您希望能够从Twitter和Facebook登录,会发生什么?只有一个提供者的空间?

我应该在帐户模型或身份验证模型上使用Devise 吗?

小智 8

最近我正在开发一个项目,我正在使用Devise为不同的服务保留用户的令牌.有点不同的情况,但你的问题仍让我想了一会儿.

无论如何,我会将Devise绑定到Account模型.为什么?让我们来看看.

由于我的电子邮件是唯一可以将我识别为用户的东西(并且您将帐户称为用户),我会将其accounts与密码配对,因此我最初能够使用基本的电子邮件/密码验证.我还要保留API令牌authentications.

正如您所提到的,OmniAuth模块需要存储提供者和ID.如果您希望您的用户能够同时连接不同的服务(并且出于某种原因),那么显然您需要将两个提供者ID对保留在某处,否则每次单个用户都会被覆盖验证.这导致我们已经适用于身份验证模型,并且引用了Account.

因此,在寻找提供者ID对时,您想要检查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
Run Code Online (Sandbox Code Playgroud)

这应该可以满足您的需求,同时保持您想要的灵活性.