Ruby
Rails
Facebook
Twitter
devise

deviseでfacebook,twitter認証

More than 5 years have passed since last update.

追記: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認証も、似たような形で追加してください。