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のカラムにprovideruidを追加します。

$ 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' }

遭遇したエラー

こんな感じの画面になりました。

Screenshot 2015-10-06 15.43.24.png 
 fbのアプリケーションの設定でひとまずdomainにlocalhostと登録してhttp://localhost:3000/にしたらいけるようになりました。

先人に感謝です。。

http://totem3.hatenablog.jp/entry/2014/07/25/084641