LoginSignup
1
6

SNSログイン機能(Google,Twitter(X),Facebook)

Last updated at Posted at 2023-09-05

SNSログイン機能


SNSログイン機能の機能実装は共通している部分が多いため、一気にGoogle, Twitter, Instagramのログイン機能を実装する。
個別で必要な時は適宜不必要な部分を削除して使用してください。

環境

OS:macOS Monterey ver 12.0.1 (M1, 2020)
Ruby:3.2.1
Rails:7.0.5
MySQL:8.0.33
OAuth:2.0

技術

OAuth
OmniAuth

Gem

全対象:Devise(認証), omniauth-rails_csrf_protection(CSRF攻撃対策)
Google認証:omniauth-google-oauth2
Twitter認証:omniauth-twitter
Facebook認証:omniauth-facebook

前提条件

Deviceを用いた新規登録・ログイン・ログアウト機能が完成している




準備


GoogleAPI登録(Google認証に必要)

前提条件

Gmailを持っている

Google Cloud Platformにログイン

Google Cloud Platformで任意の名前でプロジェクト作成

OAuth同意画面でプロジェクト詳細設定

公開ステータス:テスト
ユーザーの種類:外部
テストユーザー:開発環境で動作確認する時に使用するメールアドレス(普段使ってるGmailでOK)

認証情報画面でOAuth2.0クライアントID,クライアントシークレット発行

名前:任意の名前
承認済みのJavaScript生成元http://localhost, http://localhost:3000 (2つ記述する)
承認済みのリダイレクトURI:ログイン後にリダイレクトさせたいURLを記述
上記を記述し終えるとクライアントID, クライアントシークレットが発行されるのでメモする(漏洩注意)




TwitterAPI登録(Twitter認証に必要)

前提条件

メールアドレス・電話番号登録済みのアカウント
鍵アカでないこと

TwitterDevelopePortal でログイン

「Sign up for Free Account」から新規登録

無料・有料アカウントあるが、今回は無料アカウントでOK

「Describe all of your use case of Twitter’s data and API」欄でAPI使用目的を英語で250文字以上記述

そこまで重要なものではないので結構適当で大丈夫

プロジェクト新規作成

デフォルトで存在するプロジェクトでも可

[ プロジェクト名 ] → [ User authentication settings ]

App permissions:Request email from usersをON
Type of App:Web App, Automated App or Bot
App info:Callback URI / Redirect URL に
https://127.0.0.1:3000/users/auth/twitter/callback, http://127.0.0.1:3000/users/auth/twitter/callback を入力
🚨Twitterはlocalhostを使用できないので「127.0.0.1:3000」を使用する
WebsiteURL, Terms of service, Privacy policy:現在既に有効なWebsiteのURLを貼る

[ プロジェクト名 ] → [ Keys and tokens ]

API Key と API secretをメモ(漏洩注意)
🚨ClientID, ClientSecretは使用しないので注意




FacebookAPI登録(Facebook認証に必要)

前提条件

Facebookのアカウントを持っている

MetaforDeveloperアクセス→ [ スタート ]

Registar, Contact info, About youの3項目入力

新規アプリ作成

「ユーザーにFacebookアカウントでのログインを許可する」から作成

プロジェクト詳細設定

詳細設定後に発行されるアプリIDとapp secretをメモ(漏洩注意)




実装

Gemインストール

gem "omniauth-google-oauth2"  ## Google認証
gem "omniauth-twitter"  ##Twitter認証
gem "omniauth-facebook" ## Facebook認証
gem "omniauth-rails_csrf_protection" ## どの認証でも必要

Usersテーブルにカラム追加

db/migrate/00000000000000_devise_create_users.rbに以下のカラムを追加

t.string :provider
t.string :uid

SnsCredentialsテーブル作成

以下のように新しくSnsCredentialsテーブルを作成

class CreateSnsCredentials < ActiveRecord::Migration[7.0]
  def change
    create_table :sns_credentials do |t|
      t.string :provider
      t.string :uid
      t.references :user, type: :string, foreign_key: true
      t.timestamps
    end
  end
end

Userモデル, SnsCredentialモデルにリレーション関係記述

Userモデル

has_many :sns_credential, dependent: :destroy

SnsCredentialモデル

belongs_to :user

Userモデルのdeviseにomniauth系の記述追記

deviseでdeviseのヘルパーメソッドが使えるようになる

  devise :database_authenticatable, :registerable,
  :recoverable, :rememberable,
  :omniauthable, omniauth_providers: %i[google_oauth2 twitter facebook]

credentialsにIDとシークレット系を保存

EDITOR=vi rails credentials:edit          

ターミナル上で以下のように記述(SNS名, 変数名は適宜変更)

google:
  client_id: ID
  client_secret: シークレット

環境変数設定

config/initializer/devise.rb

config.omniauth :google_oauth2, Rails.application.credentials.google[:client_id], Rails.application.credentials.google[:client_secret], skip_jwt: true
config.omniauth :twitter, Rails.application.credentials.twitter[:client_id], Rails.application.credentials.twitter[:client_secret], skip_jwt: true
config.omniauth :facebook, Rails.application.credentials.facebook[:client_id], Rails.application.credentials.facebook[:client_secret], skip_jwt: true

Model編集

🚨Devise.friendly_token[12]の12の部分は自分のプロジェクトのパスワードの桁数のバリデーション等に応じて適宜変更
(ユーザーはSNS認証でパスワードを要求されないが、deviseの仕様としてパスワードの保存が必須なので代わりに裏側で自動的にパスワードを入れている)
user.rb

  def self.from_omniauth(auth)
    
    find_or_create_by(provider: auth.provider, uid: auth.uid) do |user|      
      user.email = auth.info.email
      user.password = Devise.friendly_token[12]
    end

  end

Controller作成

omniauth_callbacks_controller.rb作成

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def google_oauth2    
    callback_for(:google)    
  end

  def twitter
    callback_for(:twitter)
  end

  def facebook
    callback_for(:facebook)
  end

  def callback_for(provider)

    @user = User.from_omniauth(request.env['omniauth.auth'])
    @user.save!
          
    if @user.persisted?
      sign_in @user 
      redirect_to platforms_path 
    else
      redirect_to new_user_registration_path
    end

  end

  def failure
    redirect_to root_path and return
  end

end

Routing編集

  devise_for :users, controllers: {
    registrations: 'users/registrations',
    sessions: 'users/sessions',
    passwords: 'users/passwords',
    omniauth_callbacks: "users/omniauth_callbacks"
  }

Viewにボタン設置

## Google
<%= link_to user_google_oauth2_omniauth_authorize_path, method: :post do %>
  Googleアカウントでサインインする
<% end %>

## Twitter
<%= link_to user_twitter_omniauth_authorize_path, method: :post do %>
  Twitterアカウントでサインインする
<% end %>

## Facebook
<%= link_to user_facebook_omniauth_authorize_path, method: :post do %>
  Facebookアカウントでサインインする
<% end %>

補足

パスワードについて

SNS認証はパスワードはユーザーに要求されないので、ユーザー全員にt対してパスワードのバリデーションをかけている場合は、SNS認証で登録・ログインする人には要求しないようにする
(以下はproviderが存在するかどうかで判別している)

class PasswordFormatValidator < ActiveModel::EachValidator
  VALID_PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[A-Za-z\d]{8,12}\z/
  def validate_each(record, attribute, value)
    unless record.provider.present?      
      unless value =~ VALID_PASSWORD_REGEX              
        record.errors.add(attribute, (options[:message] || 'が正しい形式ではありませんんん'))
      end
    end
  end
end

authの中身

下記のようにさまざまな情報を取得することができる。
下記はauthで取得できる情報の一部なのでデバッグで確認してみてほしい。
User.rbのself.from_omniauth(auth)のメソッド内で確認可能

 {"provider"=>"twitter",
 "uid"=>"0000000000000000000",
 "info"=>
  {"nickname"=>"000000",
   "name"=>"田嶋太一",
   "email"=>"00000000@gmail.com",
   "location"=>"東京 世田谷",
   "image"=>"画像のURL",
   "description"=>"",
   "urls"=>{"Website"=>0000000, "Twitter"=>"0000000"}},
 "credentials"=>{"token"=>"0000000000000000000000", "secret"=>"Qx42N9jWKc5zjMnl8xDU3b1VJplRJEi4hqBei97vAoUzJ"},

確認

新規登録・ログインの確認

MySQLのテーブル内に登録したメールアドレス, uid, providerが保存されていて2回目以降もログイン可能で成功
🚨複数SNSで同一メアドが登録されないようにするためにメールアドレスにuniqueを適用した方が良い

まとめ

各SNSのID,シークレット取得
必要なGemインストール
Usersテーブルにカラム追加
SnsCredentialテーブル作成
User, SnsCredentialリレーション関連付け
deviseにomniauth追記
credentialsでID,シークレット管理
環境変数設定
Modelでauthのデータ取得
Controllerで各SNSの処理振り分け
Routingでomniauthのページを返せるようにする
Viewにボタン設置
(パスワードバリデーション関連)
(authデバッグ)
データベース保存確認,動作確認

🚨各バージョン、開発者ツールの画面仕様の変更等で違う場合あり

参考記事

1
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
6