創建多認證(或多供應商)應用程序的第一步是將您的用戶模型與認證分開。
請確保您在開始之前閱讀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,你可以省略提供商列。您也可以根據需要命名模型 - OathAccount
或InstagramAccount
或任何您喜歡的。
我們可以生成認證模式:
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
爲了處理這一切的邏輯,我們可能要在服務對象調用。這些只是簡單的 接受輸入並完成任務的紅寶石對象。
# 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
這使得它比測試我們的控制器中的所有邏輯容易得多。 我們可以只注入任何散列並使用我們想要的用戶對象。
只是一個小小的警告 - 我們需要告訴導軌自動載入我們的服務
# 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
:
有您創建一個單獨的模型來存儲認證? – max
@papirtiger不,你能指導我怎麼做?我會接受你的回答。我需要從一個用戶的三個Instagram應用獲取信息 –
@AigarsCibuļskis請不要污衊您的問題。 –