SNS(Facebook)ログイン機能の追加

どうもどハマりエンジニアです。

 

Facebook認証によるユーザー登録・ログイン機能を追加していきます。

 

authenticationsテーブルを作成

$ rails g sorcery:install external --only-submodules

 

migrate/2020020311301_sorcery_external.rb

class SorceryExternal < ActiveRecord::Migration[5.2]
 def change
  create_table :authentications do |t|
  t.integer :user_id, null: false
  t.string :provider, :uid, null: false

  t.timestamps null: false
 end

  add_index :authentications, [:provider, :uid]
  add_index :authentications, :user_id ←user_idにindexを貼る場合は追加
 end
end

ここでは外部認証に必要なautenticationsテーブルを作成するためのマイグレーションが作成されます。

$bundle exec rails db:migrate

 

Authenticationモデルの設定

$ rails g model Authentication --migration=false

先ほどマイグレーションファイルを作成したので、--migration=false オプションをつけます。

 

models/authentication.rb

belongs_to :user

 

models/user.rb

has_many :authentications, dependent: :destroy
accepts_nested_attributes_for :authentications

 

ここまではfacebook認証に限らず、外部認証共通の処理になります。

 

 

sorcery.rbの設定

Rails.application.config.sorcery.submodules = %i[reset_password external]

Rails.application.config.sorcery.configure do |config|
 config.external_providers = %i[twitter facebook]

 ①config.facebook.key = Rails.application.credentials.dig(:sorcery, :facebook, :key) # 1.で解説
 ①config.facebook.secret = Rails.application.credentials.dig(:sorcery, :facebook, :secret) # 1.で解説
 ②config.facebook.callback_url = 'https://localhost:3001/oauth/callback?provider=facebook' # 2.で解説
 config.facebook.user_info_path = 'me?fields=email, first_name, last_name' # 3.で解説
 config.facebook.user_info_mapping = { email: 'email', first_name: 'first_name', last_name: 'last_name' } # 3.で解説
 config.facebook.display = 'page'
 ④config.facebook.api_version = 'v8.0' # 4.で解説 
 config.facebook.parse = :json

 config.user_config do |user|
  user.reset_password_mailer = UserMailer
  user.authentications_class = Authentication
 end

 config.user_class = 'User'
end

 

①.facebook.keyとsecret

facebook.keyとsecretについてはfacebookの設定→ベーシックより参照できます。fecebook for deveropperでアカウントをまず作成し、アプリ登録をしておく必要があります。

簡単に流れを説明します。

①アカウントを作成する

②アプリ作成をする

③アプリの基本情報を入力していく。

④有効なOAuthリダイレクトURIを設定(後から説明)

 

ベーシックで確認したfacebook.keyとsecretを記載していくのですが、これは外部には漏らしたくないため、credentialsで管理します。

Rails5.2のcredential管理の方法のざっくりとした説明

config/credentials.yml.encファイルが追加され、productionアプリの秘密情報(secret)をここに保存できるようになりました。これによって、外部サービスのあらゆる認証credentialを、config/master.keyファイルまたはRAILS_MASTER_KEY環境変数にあるキーで暗号化した形で直接リポジトリに保存できます。Rails.application.secretsやRails 5.1で導入された暗号化済み秘密情報は、最終的にこれによって置き換えられます。 さらに、Rails 5.2ではcredentialを支えるAPIが用意され、その他の暗号化済み設定/キー/ファイルも簡単に扱えます。 詳しくは、Rails セキュリティガイドを参照してください。

  • config/master.keyに記述したキー情報でcredential情報を暗号化
  • 暗号化した情報はconfig/credentials.yml.encに書き込む
  • credential情報は普通に人間が読める感じで書ける
  • RailsアプリはRails.application.credentials.dig(:aws, :access_key_id)って感じで簡単に呼べる

って感じです!

<下記サイトより>

https://blog.naoshihoshi.com/entry/2018/06/18/153000

 

 

$  EDITOR="vi" bin/rails credentials:edit    

 

credentials.yml

sorcery:
  key: 'アプリIDの値'
  secret: 'app secretの値'
 

facebook for developersからマイアプリにアクセスし、「ダッシュボード」下の「設定」→「ベーシック」の画面から「アプリID」と「app secret」を確認し、記述してください。

 

②.callback_url

上記の実装を行う前に、今回はHTTPS通信を行いたいので、mkcertツールを使い、railsの開発環境でHTTPSを有効にします。

実装は簡単です。

$ brew install mkcert

$ mkcert -install

$ mkcert localhost

"/Users/ユーザーの名前/library/Application Support/mkcert"にあるローカル認証局を使っています。"localhost"という名前で新しい証明書を作成し、証明書は".localhost.pem"に、鍵は".localhost-key.pem"にあります。

 

puma.rb

if Rails.env.development?
ssl_bind '0.0.0.0', '3001', { cert: './localhost.pem', key: './localhost-key.pem' }
end

 

以上でHTTPS接続の設定は完了です。

https://localhost:3001/にアクセスして、接続が可能か確認します。注意すべきことは今回は3001で設定をしたので、facebookの有効なOAuthリダイレクトURIを設定とsorcery.rbのとこでも3001で設定をする必要があります。

 

有効なOAuth リダイレクトURI

https://localhost:3001/oauth/callback?provider=facebook

 

 

③.facebookから取得するデータ

デフォルトでfacebookから取得できるデータは以下のとおりになります。

  • id
  • first_name(名)
  • last_name(姓)
  • middle_name(ミドルネーム)
  • name(フルネーム)
  • name_format(デフォルトは{last}{first}
  • picture(プロフィール画像
  • short_name(設定されていない場合はフルネーム)

それ以外のデータを取得したい場合は、config.facebook.access_permissionsに記述します。
emailを取得するためにはfacebook側の手続きは要りませんが、それ以外にはアプリレビューが必要です。

 

今回はfirst_name、last_name、emailの3つになりますので、下記のようになります。

config.facebook.user_info_path = 'me?fields=email, first_name, last_name' # 3.で解説
config.facebook.user_info_mapping = { email: 'email', first_name: 'first_name', last_name: 'last_name' } # 3.で解説

プロフィール画像の取得方法は他と少し違うので注意が必要です。

 

 

4.APIのバージョン

facebookAPIは「Facebookログイン」の「クイックスタート」から「ウェブ」「2. JavaScriptFacebook SDKを設定する」で確認できます。

 

 

Oauth処理を行うコントローラを作成

$ rails g controller Oauths oauth callback

 

oauths_controller

class OauthsController < ApplicationController
skip_before_action :require_login

 def oauth
  login_at(auth_params[:provider])
 end

 def callback
  provider = auth_params[:provider]
  if (@user = login_from(provider))
   redirect_to root_path, notice: "#{provider.titleize}でログインしました"
  else
   begin
    @user = create_from(provider)
    reset_session
    auto_login(@user)
    redirect_to root_path, notice: "#{provider.titleize}でログインしました"
   rescue StandardError
    redirect_to root_path, alert: "#{provider.titleize}でのログインに失敗しました"
   end
  end
 end

 private

 def auth_params
  params.permit(:code, :provider)
 end
end

 

 

ログインボタンを追加

<%= link_to auth_at_provider_path(provider: :facebook), class: 'facebook-button' do %>
<%= icon 'fab', 'facebook-f' %>
<%= 'Facebookログイン' %>

 

 

ルーティングの追加

post 'oauth/callback', to: 'oauths#callback'
get 'oauth/callback', to: 'oauths#callback'
get 'oauth/:provider', to: 'oauths#oauth', as: :auth_at_provider

 

以上でfacebookによるログイン機能の実装は完了です。