LoginSignup
303
295

More than 5 years have passed since last update.

deviseでfacebook,twitter認証

Last updated at Posted at 2012-12-26

追記:Qiita「TwitterAPI Devise連携/グラフ可視化/データの効率的格納/API高速化」 にて続きを書きました。

qiitaにもある、「twitterでログイン」を実装します。
devise(railsのユーザー認証用gem)を使ってtwitter,facebookなどのOAuth認証。

今回はOAuth認証のみでdevise本来の追加認証はしません。tokenも使いません。

deviseの導入から解説していきます。

環境

  • ruby(1.9.3)
  • rails(3.2.3)
  • devise(2.0.4)
  • omniauth (1.1.0)
  • omniauth-oauth (1.0.1)
  • omniauth-oauth2 (1.0.2)
  • omniauth-facebook (1.3.0)
  • omniauth-twitter (0.0.9)

devise+omniauth認証

まずはdeviseの導入。https://github.com/plataformatec/devise を参考に。

1. Gem

以下をgemに追加

Gemfile
gem 'devise'
#omniauth
gem 'omniauth-facebook'
gem 'omniauth-twitter'

2. devise導入

$ bundle install
$ rails g devise:install
 config/inistializer/devise.rb (設定ファイル)作成

$ rails g devise user
 認証用モデル作成。今回はUserモデルにした。

$ rails g migration AddOmniToUser uid:integer
 migrationファイルにて、omniauth認証用カラム追加

3. deviseのmigration設定

migrationファイルを編集します。Omniauthableのためのカラムを追加します。
今回はtrackable以外の機能は使用しないので、その他はコメントアウトしてください。使う場合はお好みで。
trackableはログイン回数などを記録する機能です。

facebookはuidが非常に長いので、bigintにすることに注意してください!(3日はまりました)

db/migrate/*_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|

      ## Trackable
      t.integer  :sign_in_count, :default => 0
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ##Omniauthable
      t.integer :uid, :limit => 8 #bigintにする
      t.string :name
      t.string :provider
      t.string :password


      t.timestamps
    end
    add_index :users, :uid,  :unique => true
$ rake db:migrate

4. deviseのモデル編集

Userモデルを編集します。omniauthableにし、使わない機能をコメントアウトしましょう。

app/models/user.rb
class User < ActiveRecord::Base
   devise :trackable, :omniauthable
   attr_accessible :name, :password, :uid, :provider
end

5.developerサイトに登録

OAuth認証したいサイトにてアプリを作成し、IDとsecretを取得します。
twitter,facebookのdeveloperサイトでの作成法を解説。
サイトのURLを設定するので、development,production用に2つ作ると良いです。
(ここで指定するURLが異なると動かない場合があります!)

facebook

http://developers.facebook.com/
一番上のバーにある「アプリ」→右上「新しいアプリケーションを作成」
name,descriptionを記述。
herokuで作るかどうか選べますが、今回関係ないのでチェックしません。

アプリの個別ページに飛ぶので、
「アプリをFacebookに結合する方法を選択してください」でサイトのURLを記述します。
http://localhost:3000/
とでもしておきましょう。

App IDとApp Secretをメモっておきます。

twitter

https://dev.twitter.com/
ログイン後、右上のアイコンから「My Application」→「Create a New Application」で詳細を入力します。
name,descriptionを記述。websiteには実際に動かすURLのルートを。Callback URLにも同様にURLを記述。
Consumer key,Consumer secretをメモってください。

  • 注意:http://localhost:3000/ だとエラー出ます。ドメインやIPを入れてください。(なお twitterの場合、facebookと異なり、ここのURL指定が適当でも動いたりします)
  • 注意:Callback URL(ログイン完了後のredirect URL)を記述しないと動きません。なぜかここで記述したURLにはredirectされないので、なんでもいいので記述を。

6. deviseのconfig編集

OAuth認証のために、deviseを設定します。
config/initializer/devise.rb
に記述してもいいのですが、開発環境と本番環境を分けたいため、development.rbに記述します。

config/environments/development.rb
.
.
.
  Devise.setup do |config|devise@example.com"
    config.omniauth :facebook, '{ID}', '{SECRET}', :scope => 'email,user_birthday', :display => 'popup'
    config.omniauth :twitter, '{ID}', '{SECRET}', :display => 'popup'
  end

facebookではメールと誕生日も取得できるようにしてありますが、不要な場合はscopeを消してください。

7. Userモデル再編集

各種関数を追加します。

app/models/user.rb
.
.
.
  def self.new_with_session(params, session)
    super.tap do |user|
      if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
        user.email = data["email"]
      end
    end
  end


  def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
    user = User.where(:provider => auth.provider, :uid => auth.uid).first
    unless user
      user = User.create(name:auth.extra.raw_info.name,
                          provider:auth.provider,
                          uid:auth.uid,
 #                          email:auth.info.email, #emailを取得したい場合は、migrationにemailを追加してください。
                          password:Devise.friendly_token[0,20]
                          )
    end
    user
  end


  def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
    user = User.where(:provider => auth.provider, :uid => auth.uid).first
    unless user
      user = User.create(name:auth.info.nickname,
                          provider:auth.provider,
                          uid:auth.uid,
#                          email:auth.extra.user_hash.email, #色々頑張りましたがtwitterではemail取得できません
                          password:Devise.friendly_token[0,20]
                          )
    end
    user
  end

8. Controller設定

app/controllers/users/omniauth_callbacks_controller.rbを作成し、編集します。

app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    # You need to implement the method below in your model
    @user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)

    if @user.persisted?
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
      sign_in_and_redirect @user, :event => :authentication
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end

  def twitter
    # You need to implement the method below in your model
    @user = User.find_for_twitter_oauth(request.env["omniauth.auth"], current_user)

    if @user.persisted?
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Twitter"
      sign_in_and_redirect @user, :event => :authentication
    else
      session["devise.twitter_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end
end

9. route定義

config/routes.rbを設定します。
ログイン後にはrootに飛ばされるので、root定義もすると良いです。

routes.rb
  root :to => 'yourapp#index'
  devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

  devise_scope :user do
    get 'sign_in', :to => 'devise/sessions#new', :as => :new_user_session
    get 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session
  end

.
.
.

10. 確認

viewを作り、サーバーをたちあげて確認。

app/views/yourapp/index.html.erb
            <ul class="nav">
              <% if user_signed_in? %>
                <li><%= link_to 'ログアウト', destroy_user_session_path %></li>
              <% else %>
                <li><%= link_to "facebookでログイン", user_omniauth_authorize_path(:facebook) %></li>
                <li><%= link_to "twitterでログイン", user_omniauth_authorize_path(:twitter)  %></li>
              <% end %>

            </ul>

Invalid URI error が出る場合は、twitterやfacebookのURL指定が間違っています。
facebookの場合は、設定変更の反映に時間がかかる場合があります。
どうしてもダメだったらfacebook上のアプリを作りなおしてください。

11. 最後に

長かったですがお疲れ様でした!
他のOAuth認証も、似たような形で追加してください。

303
295
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
303
295