概要
RailsでFacebookログイン(OAuth)を実装する。動作環境
- Ruby on Rails 4.2.0
- Ruby 2.1.0p0
- Devise 3.4.1
- OmniAuth 1.2.2
- OmniAuth-facebook 2.0.0
- OmniAuth-twitter 1.1.0
事前準備
FacebookのAPIキーを取得する。
https://developers.facebook.com でアプリをつくる。
作成が完了したら、設定より「Add Platform」→「Website」を選択する。
サイトURLにURLを入力する。
サイトURLにURLを入力する。
Gemfile
gem 'omniauth-facebook'
config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']
end
FACEBOOK_KEYとFACEBOOK_SECRETは環境変数なので、CentOSとかの場合は ~/.bash_profile なんかを編集する。
ルーティングの設定
failureは、なんらかの原因でログインが失敗した時に、表示させるページ。
ログインボタンのリンクは
/auth/facebook
です。
get '/auth/:provider/callback', to: 'users#create', as: :auth_callback
get '/auth/failure', to: 'users#auth_failure', as: :auth_failure
コントローラー
Facebookから返ってくる情報を使って、ユーザーを作成したり、ログインさせたりします。
ログインの度に、iconや名前を更新したいので、@user.saveしています。
sign_inメソッドについては説明しませんが、current_userに該当のuserを代入しているだけです。
ログインの度に、iconや名前を更新したいので、@user.saveしています。
sign_inメソッドについては説明しませんが、current_userに該当のuserを代入しているだけです。
from_omniauth
メソッドやcontext:
:facebook_login
についてはモデルにて。env['omniauth.auth']にいろいろ情報が入っているので、引数として渡しています。
controllers/users_controller.rb
def create
if env['omniauth.auth'].present?
# Facebookログイン
@user = User.from_omniauth(env['omniauth.auth'])
result = @user.save(context: :facebook_login)
fb = "Facebook"
else
# 通常サインアップ
@user = User.new(strong_params)
result = @user.save
fb = ""
end
if result
sign_in @user
flash[:success] = "#{fb}ログインしました。"
redirect_to @user
else
if fb.present?
redirect_to auth_failure_path
else
render 'new'
end
end
end
モデル
同じメールアドレスが見つかれば、そのユーザーとしてログイン。
そうでなければ、新しくユーザーを作成します。
そうでなければ、新しくユーザーを作成します。
Facebookログインでは、パスワードが必要ありませんので、パスワードのバリデーションを無効にしています。
on: :facebook_login
を加えておいて、コントローラーでセーブする際に@user.save(context:
:facebook_login)
としています。
models/user.rb
validates :password, presence: false, on: :facebook_login
def self.from_omniauth(auth)
# emailの提供は必須とする
user = User.where('email = ?', auth.info.email).first
if user.blank?
user = User.new
end
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
user.icon = auth.info.image
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user
end
/auth/facebook を叩けば、Facebookのダイアログが表示される。
1. メールアドレスによる認証の実装
Gemfileの編集
Gemfile
gem 'devise'
インストール
$ bundle install
Deviseの各ファイルを生成
$ rails g devise:install
create config/initializers/devise.rb
create config/locales/devise.en.yml
===============================================================================
Some setup you must do manually if you haven't
yet:
1. Ensure you have defined default url
options in your environments files. Here is an example
of default_url_options appropriate for a development
environment in config/environments/development.rb:
config.action_mailer.default_url_options = {
host: 'localhost', port: 3000 }
In production, :host
should be set to the actual host of your application.
2. Ensure you have defined root_url to
*something* in your config/routes.rb.
For example:
root to:
"home#index"
3. Ensure you have flash messages in
app/views/layouts/application.html.erb.
For example:
<%= notice %>
<%= alert %>
4. If you are deploying on Heroku with
Rails 3.2 only, you may want to set:
config.assets.initialize_on_precompile = false
On config/application.rb
forcing your application to not access the DB
or load models when
precompiling your assets.
5. You can copy Devise views (for
customization) to your app by running:
rails g
devise:views
===============================================================================
Deviseを日本語化
config/locales/devise.en.yml
をdevise.ja.yml
にリネームする。
以下の内容をコピペする。
もちろんRailsアプリ自体も日本語化しておく必要がある。
もちろんRailsアプリ自体も日本語化しておく必要がある。
- devise-i18n/ja.yml at master · tigrish/devise-i18n
config/locales/devise.ja.yml
ja:
devise:
confirmations:
confirmed: アカウントを登録しました。
send_instructions: 登録方法を数分以内にメールでご連絡します。
send_paranoid_instructions: メールアドレスが登録されていれば、数分以内にアカウントを確認する方法が記載されているメールが届きます。
:
Userモデルを生成
Deviseのジェネレータを利用することで、あらかじめモジュールが定義されたモデルファイルを生成することができる。
$ rails g devise User
利用するモジュールを編集
Userモデルでは、
Fasebook認証を可能とするため
devise
メソッドによりどのモジュールを利用するかを定義できる。Fasebook認証を可能とするため
devise
メソッドに:omniauthable
も追加しておく。
app/models/user.rb
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, omniauth_providers: [:facebook]
利用できるモジュールについてはREADMEを参照。
マイグレーションの実行
rails g devise User
したときにdb/migrate/xxx_devise_create_users.rb
という名前でマイグレーションファイルも生成されている。これをDBに適用する。
$ rake db:migrate
== 20150207093749 DeviseCreateUsers: migrating ================================-- create_table(:users)
-> 0.0800s
-- add_index(:users, :email, {:unique=>true})
-> 0.0659s
-- add_index(:users, :reset_password_token, {:unique=>true})
-> 0.0528s
== 20150207093749 DeviseCreateUsers: migrated (0.1993s) =======================
サインアップフォームの表示
以上で、
この時点でユーザ登録ができる状態になっている。
http://〜/users/sign_up
にアクセスするとフォームが表示される。この時点でユーザ登録ができる状態になっている。
2. OAuthでの認証
Gemfileの編集
Gemfile
gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-twitter'
インストール
$ bundle install
8.Authenticationモデルの作成
元々あるUserモデルにカラムを追加しても良いが、複数のサービスのアカウントで同一のアカウントにログインできるようにしたいので、Userモデルが has_many する Authentication モデルを作成する。
$ rails g model authentication user_id:integer provider:string uid:string
invoke active_record
create
db/migrate/20150208043543_create_authentications.rb
create app/models/authentication.rb
invoke test_unit
create test/models/authentication_test.rb
create test/fixtures/authentications.yml
Userモデルを”has_many”とし、 AuthenticationモデルをUserモデルに”belongs_to”とする。
app/models/user.rb
class User < ActiveRecord::Base has_many:authentications, dependent: :destroy end
app/models/authentication.rb
class Authentication < ActiveRecord::Base belongs_to :user end
マイグレーションの実行
$ rake db:migrate
==
20150207101521 AddColumnsToUsers: migrating
================================
--
add_column(:users, :uid, :string)
-> 0.1305s
--
add_column(:users, :provider, :string)
-> 0.1113s
==
20150207101521 AddColumnsToUsers: migrated (0.2424s)
=======================
APIキーの取得
以下よりアプリケーションを作成する。
作成が完了したら、設定より「Add Platform」→「Website」を選択する。
サイトURLにURLを入力する(例:
サイト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の設定
上記で取得したプロバイダの各キーを設定する。
セキュリティのために各APIキーは環境変数に設定する。
開発/ステージング/本番環境と分ける場合は
セキュリティのために各APIキーは環境変数に設定する。
開発/ステージング/本番環境と分ける場合は
Rails.env.production?
などを用いて振り分ける。
config/initializers/devise.rb
Devise.setup do |config|
# ...
config.omniauth :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_SECRET']
config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end
Userモデルにfindメソッドを実装
uid
とprovider
の組み合わせは一意であり、これによりユーザを取得する。レコードに存在しない場合は作成する。
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での認証時もメールアドレスを保存する必要となる。
ここでは、
ここでは、
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コントローラにコールバック処理を実装
app/controllers/users
ディレクトリを作成し、omniauth_callbacks_controller.rb
を作ります。
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)
0 件のコメント:
コメントを投稿