【问题标题】:How do I allow several Instagram authentications per user with OmniAuth?如何使用 OmniAuth 允许每个用户进行多个 Instagram 身份验证?
【发布时间】:2015-05-19 06:12:05
【问题描述】:

我需要允许用户使用 3 个 Instagram 帐户进行身份验证。我在 Ruby On Rails 上进行开发,我正在使用Instagram OAuth

在我的Devise 配置中,我添加了config.omniauth :instagram, ENV['INSTAGRAM_client'], ENV['INSTAGRAM_secret'], {:scope => 'basic'}。这仅用于一种身份验证。我的问题是如何设置另外 2 个不同的端点以使用不同的帐户进行身份验证,以便我可以使用此 gem 分别处理它们以及如何访问它们?

【问题讨论】:

  • 您是否创建了一个单独的模型来存储身份验证?
  • @papirtiger 不,你能指导我怎么做吗?我会接受你的回答。我需要为一个用户从三个 Instagram 应用程序中获取信息
  • @AigarsCibuļskis 请不要玷污您的问题。

标签: ruby-on-rails ruby ruby-on-rails-4 oauth instagram


【解决方案1】:

创建多身份验证(或多提供商)应用的第一步是将您的用户模型与身份验证分开。

请确保在开始之前阅读https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

我们想要类似下面的东西:

class User < ActiveRecord::Base
  has_many :authentications
end

# Represents an OAuth authentication account 
class Authentication < ActiveRecord::Base
  belongs_to :user
  alidates_uniqueness_of :uid, scope: :provider
end

这是基于多提供商设置 - 如果您只打算使用 Instagram,您可以省略提供商列。您还可以随意命名模型 - OathAccountInstagramAccount 或任何您喜欢的名称。

我们可以生成认证模型:

rails g authentication uid:string provider:string user:references

我们还想添加一个数据库索引来加快查询速度,并确保每个 Twitter 帐户只有一个身份验证。所以让我们编辑迁移:

class CreateAuthentications < ActiveRecord::Migration
  def change
    create_table :authentications do |t|
      # ...
    end
    # add this line
    add_index :authentications, [:provider, :uid], unique: true
  end
end

现在我们需要处理 OAuth 回调 - 它显示在他们选择批准或拒绝应用程序的提供者对话框之后。让我们设置一条路线:

devise_for :users, skip: [:sessions], controllers: {
  omniauth_callbacks: 'users/omniauth_callbacks'
}

所以现在用户登录后,将被路由到/users/omniauth_callbacks/twitter

然后我们创建一个控制器:

# app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def instagram
     # OmniAuth creates a normalized 
     # hash of the credentials and info supplied by the provider.
     @auth_params = request.env["omniauth.auth"]
     # @todo check if authentication exists
     # @todo find user for authentication
     # @todo create account for new users
     # @todo sign user in
  end
end

为了处理所有这些逻辑,我们可能需要调用一个服务对象。这些很简单 接受输入并完成任务的 ruby​​ 对象。

# app/services/authenticate_service
class AuthenticateService      
  # @param [Hash|OmniAuth::AuthHash] auth_hash
  # @param [User|nil] current_user
  # @return [Authentication]
  def call(auth_hash, current_user = nil)
    auth = Authentication.find_or_initialize_by(uid: auth_hash[:uid], provider: auth_hash[:provider])
    if !current_user || !auth.user 
      # You need to adapt this to the provider and your user model
      user = User.new(
        name: auth_hash[:info][:full_name]
      )
    end
    auth.update(user: current_user ? current_user : user)
  end
end

与我们在控制器中包含所有逻辑相比,这使得测试变得容易得多。 我们可以注入任何哈希值并使用我们想要的用户对象。

只有一点警告 - 我们需要告诉 rails 自动加载我们的服务

# config/application.rb
config.autoload_paths += Dir[Rails.root.join('app', 'services', '{**}')]

现在让我们调用我们的服务并让用户登录

# app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def instagram
    @auth = AuthenticateService.new.call(request.env['omniauth.auth'], current_user)
    @user = @auth.user
    if user_signed_in?    
      flash[:notice] = 'You have added a new authentication!'
      redirect_to :root
    else
      sign_in_and_redirect(:user, @user)
    end
  end
end

推荐阅读:

【讨论】:

  • 这是一个相当高级的话题,您需要了解 Rails 和 OAuth 的工作原理。如果你刚开始使用 Rails,我不会牵你的手。
  • 编辑:删除了一个错误行,即使没有,也会尝试将身份验证分配给当前用户。
猜你喜欢
  • 2012-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多