DeviseでFacebookのAOuth認証を導入する
Special Thanks
- OmniAuth: Overview - devise wiki
https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
- Devise+OmniAuthでユーザ認証を実装する手順
http://qiita.com/kami30k/items/94aec2d94a2b4e9a1d0b
手順
0. さいしょに
最初に、
Remember that config.omniauth adds omniauth provider middleware to your application. This means you should not add this provider middleware again in config/initializers/omniauth.rb as they'll clash with each other and result in always-failing authentication.
ということでこれからの開発でうっかり再度omniauthのmiddlewareを追加しないように気をつけましょう。
1. 初期設定
まず、facobook用のomniauthライブラリを追加します。
# Gemfile gem "omniauth-facebook"
facebook以外のprovider一覧はこちらにあります。
https://github.com/intridea/omniauth/wiki/List-of-Strategies
次に、User
のカラムにprovider
とuid
を追加します。
$ rails g migration AddOmniauthToUsers provider:index uid:index
以下からFacebookのアプリケーションを作成します。
https://developers.facebook.com/
作成したらダッシュボードからApp IDとApp Secretを取得できるようになります。
config/initializers/devise.rb
でこれらを設定します。
Devise.setup do |config| config.omniauth :facebook, "APP_ID", "APP_SECRET", scope: "user,public_repo" end
scopeはこちら
https://developers.facebook.com/docs/facebook-login/permissions/v2.4
そしたらdeviseのincludeするmoduleにomniauthのmoduleも加えます。
# app/models/user.rb devise :omniauthable, :omniauth_providers => [:facebook]
2. omniauthのmoduleをモデルに追加
deviseの標準のパスのdevise_for :users
って設定がconfig/routes.rb
でされていれば、以下の2つのパスが生成されるようになるはずです。
$ bin/rake routes | grep "omniauth" user_omniauth_authorize GET|POST /users/auth/:provider(.:format) devise/omniauth_callbacks#passthru {:provider=>/facebook/} user_omniauth_callback GET|POST /users/auth/:action/callback(.:format) devise/omniauth_callbacks#(?-mix:facebook)
この時点で、Facebookに飛べるようになりました。次はcallbackを設定していきます!
2. Callback設定
callbackを扱うコントローラを作ります。
fbだけでよければ、以下のdeviseのwikiと同じ感じでok。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController def facebook # You need to implement the method below in your model (e.g. app/models/user.rb) @user = User.find_for_oauth(request.env["omniauth.auth"]) if @user.persisted? sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format? else session["devise.facebook_data"] = request.env["omniauth.auth"] redirect_to new_user_registration_url end end end
さきほど使ったメソッドfind_for_oauth()
を定義します。
これはこちらの記事を参考にさせていただきました。
http://qiita.com/kami30k/items/94aec2d94a2b4e9a1d0b
# 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 # Create dummy email for OAuth def self.dummy_email(auth) "#{auth.uid}-#{auth.provider}@example.com" end end
emailを必須にしている場合はこのようにdummyのemailを生成するようにするのがいいです。
そして最後に、ルーティングにさきほどのcallbackを設定します。
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
遭遇したエラー
こんな感じの画面になりました。
fbのアプリケーションの設定でひとまずdomainにlocalhost
と登録してhttp://localhost:3000/
にしたらいけるようになりました。
先人に感謝です。。