Help us understand the problem. What is going on with this article?

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

More than 3 years have 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にリダイレクトしている。

その他の参考記事

zenizh
プロダクトマネージャ/エンジニア。共著に『現場で使えるRuby on Rails 5』。妻と娘、猫とのんびり暮らしています。
https://product-development.io
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした