Edited at

Devise+OmniAuthでユーザ認証を実装する手順

More than 1 year has passed since last update.

Ruby on Railsアプリケーションに、以下の認証方法を実装する。

今回は1→2の順序で実装する。


  1. メールアドレス

  2. OAuth(Facebook/Twitter)


動作環境


  • Ruby on Rails 4.1.1

  • Devise 3.3.0

  • OmniAuth 1.2.2


全体の概要

先に以下の記事に目を通すことで、全体の概要を把握することができる。


1. メールアドレスによる認証の実装


Gemfileの編集


Gemfile

gem 'devise'



インストール

$ bundle install


Deviseの各ファイルを生成

$ rails g devise:install


Deviseを日本語化

config/locales/devise.en.ymldevise.ja.ymlにリネームし、以下の内容をコピペする。

もちろんRailsアプリ自体も日本語化しておく必要がある。


config/locales/devise.ja.yml

ja:

devise:
confirmations:
confirmed: アカウントを登録しました。
send_instructions: 登録方法を数分以内にメールでご連絡します。
send_paranoid_instructions: メールアドレスが登録されていれば、数分以内にアカウントを確認する方法が記載されているメールが届きます。

:



Userモデルを生成

Deviseのジェネレータを利用することで、あらかじめモジュールが定義されたモデルファイルを生成することができる。

$ rails g devise user


利用するモジュールを編集

Userモデルでは、deviseメソッドによりどのモジュールを利用するかを定義できる。


app/models/user.rb

# Include default devise modules. Others available are:

# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable

利用できるモジュールについてはREADMEを参照。


マイグレーションの実行

rails g devise userしたときにdb/migrate/xxx_devise_create_users.rbという名前でマイグレーションファイルも生成されている。

これをDBに適用する。

$ rake db:migrate


サインアップフォームの表示

以上で、http://〜/users/sign_upにアクセスするとフォームが表示される。

この時点でユーザ登録ができる状態になっている。


2. OAuthでの認証


Gemfileの編集


Gemfile

gem 'omniauth'

gem 'omniauth-facebook'
gem 'omniauth-twitter'


インストール

$ bundle install


カラムの追加

OmniAuthではuid(一意のID)とprovider(FacebookやTwitterなど)をカラムとして利用する。

$ rails g migration AddColumnsToUsers uid:string provider:string


マイグレーションの実行

$ rake db:migrate


APIキーの取得


Facebook

以下よりアプリケーションを作成する。

作成が完了したら、設定より「Add Platform」→「Website」を選択する。

サイトURLにURLを入力する(例:http://192.168.33.10:3000/)。


Twitter

以下よりアプリケーションを作成する。

作成が完了したら、「Settings」より以下の設定を行なう。


  1. Callback URL


    • 例:http://〜/users/auth/twitter



  2. 以下にチェックを入れる:


    • Allow this application to be used to Sign in with Twitter




参考


Deviseの設定

上記で取得したプロバイダの各キーを設定する。

開発/ステージング/本番環境と分ける場合はRails.env.production?などを用いて振り分ける。


config/initializers/devise.rb

Devise.setup do |config|

# ...

config.omniauth :facebook, 'App ID', 'App Secret'
config.omniauth :twitter, 'API key', 'API secret'
end


こちらも、実際の運用ではハードコーディングせずdotenvなどに書いた方がよい。


Userモデルにモジュールを追加

deviseメソッドに:omniauthableを追加する。


app/models/user.rb

devise :database_authenticatable, :registerable,

:recoverable, :rememberable, :trackable, :validatable, :omniauthable


Userモデルにfindメソッドを実装

uidproviderの組み合わせは一意であり、これによりユーザを取得する。

レコードに存在しない場合は作成する。


app/models/user.rb

class User < ActiveRecord::Base

# ...

def self.find_for_oauth(auth)
user = User.where(uid: auth.uid, provider: auth.provider).first

unless user
user = User.create(
uid: auth.uid,
provider: auth.provider,
email: User.dummy_email(auth),
password: Devise.friendly_token[0, 20]
)
end

user
end

private

def self.dummy_email(auth)
"#{auth.uid}-#{auth.provider}@example.com"
end
end


メールアドレスでの認証も実装している場合、OAuthでの認証時もメールアドレスを保存する必要がある。

ここでは、uidproviderの組み合わせが一意なことを利用して、self.dummy_emailのように生成している。


参考


Userコントローラにコールバック処理を実装

providerと同じ名前のメソッドを定義する必要がある。

ただ、基本的に各プロバイダでのコールバック処理は共通しているので、callback_fromメソッドに統一している。


app/controllers/users/omniauth_callbacks_controller.rb

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

def facebook
callback_from :facebook
end

def twitter
callback_from :twitter
end

private

def callback_from(provider)
provider = provider.to_s

@user = User.find_for_oauth(request.env['omniauth.auth'])

if @user.persisted?
flash[:notice] = I18n.t('devise.omniauth_callbacks.success', kind: provider.capitalize)
sign_in_and_redirect @user, event: :authentication
else
session["devise.#{provider}_data"] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
end
end



ルーティング処理

以下のように、OAuthのコールバック用のルーティングを設定する。


config/routes.rb

Rails.application.routes.draw do

devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

# ...
end



認証用リンクを追加

以下によりリンクが生成される。

これをビューの任意の位置に記述する。

user_omniauth_authorize_path(:facebook)

user_omniauth_authorize_path(:twitter)


メモ


persisted?メソッドについて

.persisted?は、レシーバがデータベースに保存済みかどうかを確認する。

上の例では、保存に失敗したらusers/sign_upにリダイレクトしている。


その他の参考記事