12

我有一个简单的解决方案,我用以下对象制作了自己:

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

我有一个单独的身份验证模型,能够连接多种登录方式(设备 UUID、电子邮件/密码、推特、脸书等)。但似乎在设计的所有示例中,您都在用户帐户)模型上使用它。

是不是不太灵活?例如 OmniAuth 模块在User模型上存储 provider 和 id,如果您希望能够同时从 Twitter 和 Facebook 登录会发生什么,只有一个 provider 的空间?

我应该在我的Account模型还是Authentication模型上使用 Devise?

4

2 回答 2

8

最近一直在做一个项目,我正在使用 Devise 为不同的服务保留用户的令牌。有点不同的情况,但你的问题仍然让我思考了一段时间。

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

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

正如您所提到的,OmniAuth 模块需要存储提供者和 id。如果您希望您的用户能够同时连接到不同的服务(并且出于某种原因您这样做),那么显然您需要将两个 provider-id 对保存在某个地方,否则每次单个用户都会简单地覆盖一个认证。这将我们引向Authentication模型,该模型已经适合该模型并引用了Account

因此,在寻找提供者 ID 对时,您要检查authenticationstable 而不是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

这应该给你你需要的东西,同时保持你想要的灵活性。

于 2013-02-09T15:40:06.920 回答
1

您可以将所有常见逻辑分离到模块并仅使用同一张表。

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

这将为管理模型创建设计。

更多信息在这里

于 2013-02-01T14:24:22.977 回答