今回は、事前に作成したDeviseによる認証機能とは別に、TwitterやFacebookアカウントで認証できるように実装していきます。
1.gemの追加。
Gemfile
gem 'devise'
gem 'omniauth'
gem 'omniauth-twitter'
gem 'omniauth-facebook'
$ bundle install
2.UserモデルにOmniAuthで利用するカラムを追加。
$ bundle exec rails generate migration AddOmniauthColumnsToUsers provider uid name
class AddOmniauthColumnsToUsers < ActiveRecord::Migration
def change
add_column :users, :uid, :string, null: false, default: ""
add_column :users, :provider, :string, null: false, default: ""
add_column :users, :name, :string
add_index :users, [:uid, :provider], unique: true
end
end
$ bundle exec rake db:migrate
uid, provider, name の3つのカラムが追加されました。
3.OAuth認証に必要なキー・シークレットトークンを追記。
(1)Facebook の API Key
Home – Facebook開発者 で取得。https://developers.facebook.com/
ログイン → 右上の「Register Now」から developer 登録。
Facebook Developers の右上の「+新しいアプリを作成」。
・アプリ名:任意
・名前空間:任意
・カテゴリ:その他(任意)
と入力して、App ID, App Secret を取得。
アプリをFacebookに結合する方法を選択で、Facebookでログインが可能なウェブサイトに「http://localhost:3000」を入力。
(2)Twitter の API Key
Twitter Developers で取得。https://dev.twitter.com/
ログイン → 右上 My Applications → Create a new application
・Name:任意
・Description:任意
・Website:適当なURL(http://localhost:3000 だとNG)
・Callback URL:http://127.0.0.1:3000/auth/twitter/callback
(http://localhost:3000 だとNG)
その後、Consumer key, Consumer secret を取得し、 key, secret を config/initializers/devise.rb に設定。
Settings で 「Allow this application to be used to Sign in with Twitter」にチェック。一回TwitterでOAuth認証を行うと、次回からは確認画面が省略される。
# API key
if Rails.env.production?
config.omniauth :facebook, "App ID", "App Secret"
config.omniauth :twitter, "Consumer key", "Consumer secret"
else
config.omniauth :facebook, "App ID", "App Secret"
config.omniauth :twitter, "Consumer key", "Consumer secret"
end
4.Userモデルにomniauthableを追加。
devise :database_authenticatable, :omniauthable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
5.OAuthのcallback 用ルーティングを追加。
devise_for :users, :controllers => {
:sessions => "users/sessions",
:registrations => "users/registrations",
:passwords => "users/passwords",
:omniauth_callbacks => "users/omniauth_callbacks"
}
6.Users::OmniauthCallbacksControllerを作成。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
@user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if @user.persisted?
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
sign_in_and_redirect @user, :event => :authentication
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def twitter
# You need to implement the method below in your model
@user = User.find_for_twitter_oauth(request.env["omniauth.auth"], current_user)
if @user.persisted?
set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
sign_in_and_redirect @user, :event => :authentication
else
session["devise.twitter_data"] = request.env["omniauth.auth"].except("extra")
redirect_to new_user_registration_url
end
end
end
※deviseのコントローラー作成は以下のとおり。
$ rails g devise:controllers users
以下のControllerが生成される。
confirmations_controller.rb
omniauth_callbacks_controller.rb
passwords_controller.rb
registrations_controller.rb
sessions_controller.rb
unlocks_controller.rb
7.通常サインアップ時の uid フィールド設定の実装。
class Users::RegistrationsController < Devise::RegistrationsController
def build_resource(hash=nil)
hash[:uid] = User.create_unique_string
super
end
end
class User < ActiveRecord::Base
# ・・・
# 通常サインアップ時のuid用、Twitter OAuth認証時のemail用にuuidな文字列を生成
def self.create_unique_string
SecureRandom.uuid
end
# ・・・
end
8.OAuth 認証時の email フィールド設定の実装。
devise :database_authenticatable, :omniauthable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(name: auth.extra.raw_info.name,
provider: auth.provider,
uid: auth.uid,
email: auth.info.email,
password: Devise.friendly_token[0,20]
)
end
user
end
def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(name: auth.info.nickname,
provider: auth.provider,
uid: auth.uid,
email: User.create_unique_email,
password: Devise.friendly_token[0,20]
)
end
user
end
# 通常サインアップ時のuid用、Twitter OAuth認証時のemail用にuuidな文字列を生成
def self.create_unique_string
SecureRandom.uuid
end
# twitterではemailを取得できないので、適当に一意のemailを生成
def self.create_unique_email
User.create_unique_string + "@example.com"
end
9ビューにOAuth認証用のログインへのリンクを表示。
<%= link_to "Sign in with Facebook", user_omniauth_authorize_path(:facebook), :class => 'navbar-link' %>
<%= link_to "Sign in with Twitter", user_omniauth_authorize_path(:twitter), :class => 'navbar-link' %>
以上で終了です。