はじめに
今作っているアプリケーションでFacebookログインすることにしたので、調べながら実装した。
先人の記事とREADMEを読みながらすすめると割りとすぐにできたので人の優しさに感謝
実装
Gemのインストール
まずは必要なGemのインストールを行う。
今回はdeviseとfacebook-oauthを使って実装するのでこの2つをGemfileに追加する。
gem 'devise'
gem 'omniauth-facebook'
追加したらbunldeを実行する
$ bundle
deviseの設定ファイルを生成する
それでは、deviseの設定ファイルなどを生成する。
ターミナルで以下を実行する。
$ rails g devise:install
deviseのモデルを生成する
今回はUserモデルを作成した。
$ rails g devise user
生成されたマイグレーションファイルで管理したいユーザーのカラムを追加する。
あと、このカラムは必須なので忘れずに追加する。
t.string :provider
t.string :uid
マイグレーションファイルの編集が済んだらmigrateを実行する。
$ bundle exec rake db:migrate
Facebookにアプリを登録する
Facebookにアプリを登録してidとsecret_idをもらってくる。
ここにアクセスして自分のアプリを登録する。
https://developers.facebook.com/
deviseに設定
devise.rbにFacebookに登録したアプリのapp idとapp secretを登録する。
べたでの登録は危ないので、secrets.ymlとか環境変数とかに書いたのを読み込むようにすると良さげ。
Devise.setup do |config|
config.omniauth :facebook, Rails.application.secrets.facebook[:app_id], Rails.application.secrets.facebook[:app_secret]
callback_urlが必要なこともある
config.omniauth :facebook,
Rails.application.secrets.facebook[:app_id], Rails.application.secrets.facebook[:app_secret],
callback_url: Rails.application.secrets.facebook[:callback_url]
モデルをomuniauthableにする
デフォルトではomuniauthを使えるようになっていないので、モデルに記述を追加して使えるようにする。
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, omniauth_providers: [:facebook]
end
ルーティングを追加する
Facebookの認証後に処理を行うためのコールバックに必要なUルーティングを追加する。
devise_for :users,
controllers: {
omniauth_callbacks: 'users/omniauth_callbacks'
}
リンクを表示する
Facebookの認証に飛ばすためのURLをもったリンクを任意のビューに追加する。
使っているテンプレートエンジンがSlimなもので、サンプルコードもSlimで失礼
= link_to 'Facebookでログイン', user_facebook_omniauth_authorize_path
コールバック時の処理を行う
コールバックが呼ばれたときに行う処理を記述する。
コントローラを用意する。
ルーティングでusers/omuniauth_coallbacksとしているので、app/controllers/users/omniauth_callbacks_controller.rb
を追加する。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
end
コールバックは、プロバイダと同じ名前のアクションを定義してその中で実装する。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
@user = User.from_omniauth(request.env['omniauth.auth'])
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
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
def failure
redirect_to root_path, alert: 'Facebook認証に失敗しました。'
end
end
ソースコードについて
-
request.env["omniauth.auth"]
にOmniAuthがFacebookから取得した情報がハッシュとして登録されている。 - 有効なユーザーが見つかると、Deviseメソッド(sign_inまたはsign_in_and_redirect)でログインできる。
- ユーザーが永続化されていない場合は、OmuniAuthのデータをセッションに格納する。データは、deviseをキー名前空間として使用して保存する。deviseがdeviseで始まるキーのデータ尾を削除してくれるので便利。毎回自動的にリフレッシュされたセッションを得ることができる。
モデルにfrom_omniauthメソッドを定義する
app/controllers/users/omniauth_callbacks_controller.rbにfrom_omniauthメソッドがあるけど、まだ定義していないので、Userモデルにメソッドを定義する。
providerとuidで検索して、存在してればデータを取得し、なければ、データを保存するようにしている。
nameやavatarは該当するカラムが必要。
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.name = auth.info.name
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.avatar = auth.info.image
end
end
最後に
自分はこれで上手くいった、、、、と思っている
もし上手く行かなかった場合や、間違いや、ここはこうした方がよいなどあったら教えてください。
参考
GitHub devise
GitHubdevise(Wiki OmuniAuth)
Devise+OmniAuthでユーザ認証を実装する手順
Fecebookログインが急にエラーになった時の対応
疑問
providerとuidで検索するならindex貼ったほうが良いのかな??