sorceryでFacebookログインを実装する
個人的に最近deviceではなくsorceryを使うことが多くなりました。deviceと比較してsorceryの良い点として、必要な機能だけを使えるという所です。
今回はsorceryを使ってFacebookログインを実装する方法を紹介します。
初期設定
# Gemfile gem 'sorcery' # bundle install ~ bundle install --path vendor/bundle # sorceryの初期ファイルのインストール ~ bundle exec rails g sorcery:install # Facebookログインを実装するためのファイル等インストール ~ bundle exec rails g sorcery:install external --only-submodules # Authentication Model作成 ~ bundle exec rails g model Authentication --migration=false
設定ファイル
# config/routes.rb post 'logout', to: 'users/sessions#destroy', as: 'logout' get 'oauth/callback', to: 'oauth#callback' get 'oauth/:provider', to: 'oauth#oauth', as: 'auth_at_provider'
# config/initializers/sorcery.rbの該当部分に以下を追記 Rails.application.config.sorcery.configure do |config| config.external_providers = [:facebook] config.facebook.key = Settings.facebook[:key] config.facebook.secret = Settings.facebook[:secret] config.facebook.callback_url = Settings.facebook[:callback_url] config.facebook.display = "page" # 以下3つは取得したい項目と合わせて変更する config.facebook.user_info_mapping = { email: "email", name: "name", gender: "gender" } config.facebook.user_info_path = "me?fields=email,name,gender" config.facebook.access_permissions = ["public_profile", "email"] config.user_config do |user| user.authentications_class = Authentication end end
Migration
# db/migrate/xxxxxxxxxxx_sorcery_core.rb class SorceryCore < ActiveRecord::Migration def change create_table :users do |t| t.string :email, null: false t.timestamps end add_index :users, :email, unique: true end end
# db/migrate/xxxxxxxxxxx_sorcery_external.rb class SorceryExternal < ActiveRecord::Migration def change create_table :authentications do |t| t.integer :user_id, null: false t.string :provider, null: false t.string :uid, null: false t.timestamps end add_index :authentications, [:provider, :uid], unique: true, name: 'ui_authentications_01' end end
Model
# app/model/user.rb class User < ApplicationRecord authenticates_with_sorcery! do |config| config.authentications_class = Authentication end has_many :authentications, dependent: :destroy accepts_nested_attributes_for :authentications validates :email, presence: true, uniqueness: true end
# app/model/authentication.rb class Authentication < ApplicationRecord belongs_to :user validates :user_id, presence: true validates :provider, uniqueness: { scope: :uid } end
Controller
# app/controllers/app_controller.rb class ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :require_login # もしログインを必要としない場合は以下を該当のControllerに記述する # skip_before_action :require_login private def not_authenticated redirect_to login_path, alert: "ログインが必要です" end end
# app/controllers/users/sessions_controller.rb class Users::SessionsController < ApplicationController def destroy logout redirect_to root_path, notice: 'ログアウトしました' end end
# app/controllers/oauth_controller.rb class OauthController < ApplicationController skip_before_action :require_login def oauth login_at(params[:provider]) end def callback provider = params[:provider] if @user = login_from(provider) redirect_to root_path, notice: 'ログインに成功しました' else begin @user = create_from(provider) reset_session auto_login(@user) redirect_to root_path, notice: 'ログインに成功しました' rescue redirect_to root_path, alert: 'ログインに失敗しました' end end end private def auth_params params.permit(:code, :provider) end end
View
# ログイン配置したいところに以下のコードを記述 <%= link_to 'Login with Facebook', auth_at_provider_path(provider: :facebook) %>