Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

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
Webサービスとアプリづくりが趣味。新卒で上場企業→4ヶ月で退職し起業→失敗しフリーランス→スタートアップなど数社→Webサービスのみで暮らせるようになりました。共著に『現場で使えるRuby on Rails 5』。ふだんは会社員をしつつ、副業でWebサービスを運営しています。
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