OmniAuthを使ってfacebookログインする
公式: https://github.com/intridea/omniauth
タイトル通りRails(じゃなくても出来る。Sinatraとかもサポートされている)で、facebookへのログインを行ってアカウント情報なりを利用するようなパターン(ソーシャルログインなり登録時の情報の自動設定なり)を行う場合には、omniauthでサポートされているfacebook strategyを使えば簡単にできちゃう模様
facebook APIの設定
https://developers.facebook.com からアプリケーションを作成しアプリケーションIDとシークレットキーをコピーする。でValid OAuth Redirect URIsっていう所に認証後にリダイレクト先を指定しておかないとOAuth failureするので設定しておく
とりあえずはfacebook側の設定はこんだけ
Gemfile
source "https://rubygems.org"
gem "omniauth-facebook"
# テストで使うので
gem "rspec-rails", group: :test
gem "capybara-rails", group: :test
まぁ設定したらbundle install
config/initializers/omniauth.rb
ドキュメント(README.md)通りにconfig/initializers/omniauth.rbを作る
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook,
"[APP ID]",
"[APP SECRET KEY]",
# facebook appで設定したリダイレクト先と合致するように設定
:callback_path => "/auth/facebook/callback"
on_failure do |env|
# 認証をキャンセルしたりだとかした場合等に/auth/failureにぶっ飛ばす
OmniAuth::FailureEndpoint.new(env).redirect_to_failure
end
end
omniauth-facebookに関しての設定項目は https://github.com/mkdynamic/omniauth-facebook を参照
config/routes.rb
auth_facebook_callback GET /auth/facebook/callback(.:format) sessions#callback auth_failure GET /auth/failure(.:format) sessions#failure accounts GET /accounts(.:format) accounts#index
っていうようなルーティングを作るので
Rails.application.routes.draw do
get "/auth/facebook/callback" => "sessions#callback"
get "/auth/failure" => "sessions#failure"
resources :accounts
end
ってな感じでSessionsControllerとAccountsControllerが必要なので(ry
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def callback
session[:auth] = auth_hash
redirect_to :controller => :accounts
end
def failure
render :status => 500, :text => "error"
end
private
def auth_hash
request.env["omniauth.auth"]
end
end
んな感じで
app/controllers/accounts_controller.rb
class AccountsController < ApplicationController
def index
auth = session[:auth]
return redirect_to "/auth/failure" if auth.nil?
# :authがOmniAuthのAuthHashを検証するような場合
# 詳しくはhttps://github.com/intridea/omniauth/blob/master/lib/omniauth/auth_hash.rb#L19
# OmniAuth::AuthHash.new(auth).valid?
@user = auth
end
end
な感じでapp/views/accounts/index.erbで
name = <%= @user["info"]["nickname"] %>
な感じでnicknameを出力しているだけ。
まぁ要は/auth/facebookにアクセスしアクセス許可を承認されると /auth/facebook/callbackに行って、セッションデータにログイン時のユーザー情報を格納後/accountsにリダイレクト、そこで最終的に情報が表示されるような感じ
spec/rails_helper.rb
RSpec3(+Rails)辺りからはspec/rails_helper.rbにRailsに特有される設定等を行う模様げっぽいので
# ここから追加
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({
:provider => "facebook",
:info => {
:nickname => "hoge"
}
})
require "capybara/rails"
require "capybara/rspec"
# ここまで
RSpec.configure do |config|
# 追加
config.include Capybara::DSL
end
な感じでOmniAuth.config.test_modeを使用する事でテスト時には/auth/facebook等にリクエストした場合は問答無用でコールバック先にリダイレクトされる模様。でその際のomniauth.authなのはOmniAuth.config.mock_authで設定する事が可能。んまぁこういうところはテストを実行する前にbefore :each等で設定するべきなんじゃないのかなって思う
spec/requests/auth_spec.rb
require "rails_helper"
describe "oauth callback test", :js => false do
before :each do
page.driver.options[:follow_redirects] = true
end
it "/auth/facebookにリクエストした場合 (リダイレクトをフォローしない場合" do
page.driver.options[:follow_redirects] = false
visit "/auth/facebook"
# /auth/facebookにアクセスするとOmniAuth.config.test_modeによりcallbackへ飛ばされる
expect(page.status_code).to be(302)
# /auth/facebookから飛ばされた先が/auth/facebook/calbackかをテスト
expect(page.response_headers["Location"]).to match(%r!/auth/facebook/callback$!)
end
it "/auth/facebookにリクエストした場合 (リダイレクトをフォローする場合" do
visit "/auth/facebook"
# /auth/facebook -> /auth/facebook/callback -> /accounts にぶっ飛ぶ
expect(page.status_code).to be(200)
# OmniAuth.config.mock_authで指定しているデータにより、{ info => { nickname => "hoge" }}が作用してレンダリングされているか検証
expect(page).to have_content("name = hoge")
end
it "/auth/facebook/callbackに直接リクエストした場合" do
visit "/auth/facebook/callback"
# 一個上のテストと同様
expect(page.status_code).to be(200)
expect(page).to have_content("name = hoge")
end
it "OmniAuth.config.mock_authに:invalid_credentialsを指定した場合" do
page.driver.options[:follow_redirects] = false
OmniAuth.config.mock_auth[:facebook] = :invalid_credentials
visit "/auth/facebook/callback"
# :invalid_credentialsをした場合にon_failureで指定している/auth/failureへぶっ飛ぶ事を検証
expect(page.status_code).to be(302)
expect(page.response_headers["Location"]).to match(%r!/auth/failure?.*!)
end
end
終わり。っていう事で若干適当感がハンパないけどomniauthとomniauth strategyを使えば簡単にソーシャルログイン等を使ってデータを取得したり出来るんじゃないかと
余談としてomniauthで使えるstrategyは https://github.com/intridea/omniauth/wiki/List-of-Strategies に載ってるので使いたいサービスとかに対応するのを使えば良いっぽい
追記1: omniauthのURL prefixを変える方法
デフォルトだと/authになっていて、それがStrategyを含むと/auth/:providerっていう感じになるわけなんだけど、それのprefixを変えたい場合
Rails.application.config.middleware.use OmniAuth::Builder do
configure do |config|
config.path_prefix = "/user/auth"
end
# 以降省略
end
ってな感じにすれば良いらしい