いつも同じことするたびに手間がかかるのでいい加減にメモっておく「Devise + OmniAuth」編。
DeviseとOmniAuthで複数のソーシャルサービス経由でログインできるようにする。
環境
Rails 4.2.7
ruby 2.3.3
Gemfile
gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-twitter'
$ bundle install
Authentication モデルを作成
$ bundle exec rails g model Authentication user_id:integer provider:string uid:string
migrationファイル
class CreateAuthentications < ActiveRecord::Migration
def change
create_table :authentications do |t|
t.references :user, index: true, foreign_key: true, null: false
t.string :provider, null: false
t.string :uid, null: false
t.timestamps null: false
end
add_index :authentications, [:provider, :uid], unique: true
end
end
$ bundle exec rake db:migrate
app/models/authentication.rb
class Authentication < ActiveRecord::Base
belongs_to :user
validates :user_id, :uid, :provider, presence: true
validates :uid, uniqueness: { scope: :provider }
validates :provider, inclusion: { in: ["twitter", "facebook"] }
end
app/models/users.rb
class User < ActiveRecord::Base
devise :omniauthable, :omniauth_providers => [:facebook, :twitter]
validates :name, presence: true, length: { maximum: 24 }, uniqueness: true, case_sensitive: false, format: { with: /\A[a-zA-Z0-9_]+\Z/ }
has_many :authentications, :dependent => :destroy
:
app/controller/application_controller.rb
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :email, :password, :password_confirmation])
devise_parameter_sanitizer.permit(:sign_in, keys: [:name, :password])
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end
app/controller/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
def build_resource(hash=nil)
if hash.empty?
if session[:omniauth].try(:[], 'provider') == 'facebook'
hash[:email] = session[:omniauth]['info']['email']
hash[:name] = session[:omniauth]['info']['name']
elsif session[:omniauth].try(:[], 'provider') == 'twitter'
hash[:name] = session[:omniauth]['info']['name']
end
end
super
end
def create
super
if session[:omniauth].try(:[], 'provider') && @user.persisted?
@user.authentications.create(provider: session[:omniauth]['provider'], uid: session[:omniauth]['uid'])
session.delete(:omniauth)
end
end
app/controller/authentications_controller.rb
class AuthenticationsController < ApplicationController skip_before_action :require_login, only: :create def all omniauth = request.env["omniauth.auth"] authentication = Authentication.find_by_provider_and_uid(omniauth.provider, omniauth.uid) if authentication && current_user.nil? flash[:notice] = "ログインしました。" sign_in_and_redirect(authentication.user) elsif authentication && authentication.try(:user_id) != current_user.id flash[:notice] = "この#{omniauth.provider}アカウントは、別のアカウントと既に連携されています。" redirect_to edit_user_registration_url elsif current_user current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid']) flash[:notice] = "アカウントの #{omniauth.provider} 連携を設定しました。" redirect_to root_url() else session[:omniauth] = omniauth.except('extra') redirect_to new_user_registration_url end end # DELETE /authentications/:id def destroy provider = params[:provider] authorization = current_user.authentications.find_by_provider_and_user_id(provider, current_user.id) authorization.destroy redirect_to root_url, notice: "アカウントの #{provider} 連携を解除しました。" end alias_method :facebook, :all alias_method :twitter, :all end
routes.rb
devise_for :users, controllers: {
registrations: 'users/registrations',
sessions: 'users/sessions',
omniauth_callbacks: 'authentications'
}
get '/auth/:provider/callback' => 'authentications#facebook'
delete "/auth/destroy/:provider" => 'authentications#destroy', as: :destroy_connection
devise_scope :user do
get "sign_in", :to => "users/sessions#new"
get "sign_out", :to => "users/sessions#destroy"
end
アプリ登録
facebook https://developers.facebook.com/
APP_ID: ******
APP_SECRET: ******
Facebookログイン > クライアントOAuth設定> 有効なOAuthリダイレクトURI: http://hogehoge.dev http://hogehoge.com
Twitter https://apps.twitter.com/
Consumer Key (API Key) ******
Consumer Secret (API Secret) ******
Callback URL: http://hogehoge.com/auth/twitter/callback
config/initializers/devise.rb
config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
config.omniauth :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_SECRET']
edit.html.haml
%h3= "SNS Account"
- if current_user.authentications.find_by_provider(:facebook)
%p= link_to "unconnect facebook", destroy_connection_path(:facebook), method: :delete, data:{confirm:"Sure?"}
- else
%p= link_to "connect facebook", user_facebook_omniauth_authorize_path
- if current_user.authentications.find_by_provider(:twitter)
%p= link_to "unconnect twitter", destroy_connection_path(:twitter), method: :delete, data:{confirm:"Sure?"}
- else
%p= link_to "connect twitter", user_twitter_omniauth_authorize_path
コメントを残す