Ruby on Railsアプリケーションに、以下の認証方法を実装する。
今回は1→2の順序で実装する。
- メールアドレス
- OAuth(Facebook/Twitter)
動作環境
- Ruby on Rails 4.1.1
- Devise 3.3.0
- OmniAuth 1.2.2
全体の概要
先に以下の記事に目を通すことで、全体の概要を把握することができる。
- http://post.simplie.jp/posts/43
- http://qiita.com/mosa_siru/items/9f1faa509f4d3653a1b2
- http://qiita.com/ytkt/items/d78841f7dea5e29f38ee
- http://easyramble.com/implement-devise-and-ominiauth-on-rails.html
- https://github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview
1. メールアドレスによる認証の実装
Gemfileの編集
gem 'devise'
インストール
$ bundle install
Deviseの各ファイルを生成
$ rails g devise:install
Deviseを日本語化
config/locales/devise.en.yml
をdevise.ja.yml
にリネームし、以下の内容をコピペする。
もちろんRailsアプリ自体も日本語化しておく必要がある。
ja:
devise:
confirmations:
confirmed: アカウントを登録しました。
send_instructions: 登録方法を数分以内にメールでご連絡します。
send_paranoid_instructions: メールアドレスが登録されていれば、数分以内にアカウントを確認する方法が記載されているメールが届きます。
:
Userモデルを生成
Deviseのジェネレータを利用することで、あらかじめモジュールが定義されたモデルファイルを生成することができる。
$ rails g devise user
利用するモジュールを編集
Userモデルでは、devise
メソッドによりどのモジュールを利用するかを定義できる。
# 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の編集
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キーの取得
以下よりアプリケーションを作成する。
作成が完了したら、設定より「Add Platform」→「Website」を選択する。
サイトURLにURLを入力する(例:http://192.168.33.10:3000/
)。
以下よりアプリケーションを作成する。
作成が完了したら、「Settings」より以下の設定を行なう。
- Callback URL
- 例:
http://〜/users/auth/twitter
- 以下にチェックを入れる:
- Allow this application to be used to Sign in with Twitter
参考
Deviseの設定
上記で取得したプロバイダの各キーを設定する。
開発/ステージング/本番環境と分ける場合はRails.env.production?
などを用いて振り分ける。
Devise.setup do |config|
# ...
config.omniauth :facebook, 'App ID', 'App Secret'
config.omniauth :twitter, 'API key', 'API secret'
end
こちらも、実際の運用ではハードコーディングせずdotenv
などに書いた方がよい。
Userモデルにモジュールを追加
devise
メソッドに:omniauthable
を追加する。
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
Userモデルにfindメソッドを実装
uid
とprovider
の組み合わせは一意であり、これによりユーザを取得する。
レコードに存在しない場合は作成する。
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での認証時もメールアドレスを保存する必要がある。
ここでは、uid
とprovider
の組み合わせが一意なことを利用して、self.dummy_email
のように生成している。
参考
- http://stackoverflow.com/questions/18504308/getting-omniauth-facebook-and-omniauth-twitter-work
- http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/
- http://easyramble.com/devise-and-omniauth-specs.html
Userコントローラにコールバック処理を実装
provider
と同じ名前のメソッドを定義する必要がある。
ただ、基本的に各プロバイダでのコールバック処理は共通しているので、callback_from
メソッドに統一している。
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のコールバック用のルーティングを設定する。
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
にリダイレクトしている。
- http://railsdoc.com/references/persisted%3F
- http://stackoverflow.com/questions/9211548/rails-3-1-devise-oauth-for-facebook-routing-confusion