追記: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に追加
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日はまりました)
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にし、使わない機能をコメントアウトしましょう。
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が異なると動かない場合があります!)
http://developers.facebook.com/
一番上のバーにある「アプリ」→右上「新しいアプリケーションを作成」
name,descriptionを記述。
herokuで作るかどうか選べますが、今回関係ないのでチェックしません。
アプリの個別ページに飛ぶので、
「アプリをFacebookに結合する方法を選択してください」でサイトのURLを記述します。
http://localhost:3000/
とでもしておきましょう。
App IDとApp Secretをメモっておきます。
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に記述します。
.
.
.
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モデル再編集
各種関数を追加します。
.
.
.
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を作成し、編集します。
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定義もすると良いです。
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を作り、サーバーをたちあげて確認。
<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認証も、似たような形で追加してください。