0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DeviseのRailsアプリにGoogleログイン機能を追加する

0
Posted at

はじめに

Railsアプリに Googleログイン機能を追加したので、備忘録としてまとめます。
今回は、Devise を導入しているアプリに Googleログイン機能を追加します。

環境

  • Ruby 3.3.6
  • Rails 7.2
  • PostgreSQL
  • Devise
  • Docker / Docker Compose

大まかな手順は以下です。

  • gemを追加する
  • usersテーブルにカラムを追加する(provider, uid)
  • Userモデルを omniauthable に対応させる
  • DeviseにGoogle OAuthの設定を追加する
  • Google CloudでOAuthクライアントを作成する
  • callback用のコントローラーを作成する
  • routesを設定する
  • ログイン画面 / 新規登録画面にGoogleログインボタンを追加する
  • 動作確認をする

1. gemインストール

Gemfile
gem "omniauth-google-oauth2"
gem "omniauth-rails_csrf_protection"

•omniauth-google-oauth2 は Googleログイン用の gem
•omniauth-rails_csrf_protection は CSRF対策用の gem

gemを追加したらbundle installします。

besh
bundle install

2. usersテーブルに provider と uid を追加する

Googleログインしたユーザーを識別するため、usersテーブルにproviderとuidを追加します。

bash
bin/rails generate migration AddOmniauthToUsers provider:string uid:string

生成されたmigrationファイルを以下のように修正します。

rb
class AddOmniauthToUsers < ActiveRecord::Migration[7.2]
  def change
    add_column :users, :provider, :string
    add_column :users, :uid, :string

    add_index :users, [:provider, :uid], unique: true
  end
end

migrationを実行します。

bash
bin/rails db:migrate

3. UserモデルをOmniAuthに対応させる

次に、User モデルを Googleログインに対応させます。

app/models/user.rb の devise に、omniauthable を追加します。

rb
devise :database_authenticatable, :registerable,
       :recoverable, :rememberable, :validatable,
       :confirmable, :omniauthable, omniauth_providers: %i[google_oauth2]

追記した内容

rb
:omniauthable, omniauth_providers: %i[google_oauth2]

何をしているか

•  :omniauthable

OmniAuthを使った外部認証を有効にする設定です。

•  omniauth_providers: %i[google_oauth2]

使用する外部認証プロバイダを指定しています。
今回は Googleログインのみ追加するので google_oauth2 を指定しています。

4. DeviseにGoogle OAuthの設定を追加する

config/initializers/devise.rb に Google OAuth の設定を追加します。

rb
config.omniauth :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"]

何をしているか

•  :google_oauth2

Googleログインを使う設定です。

•  ENV["GOOGLE_CLIENT_ID"]

Google Cloud で取得した Client ID を読み込みます。

•  ENV["GOOGLE_CLIENT_SECRET"]

Google Cloud で取得した Client Secret を読み込みます。
Client ID / Client Secret はコードに直書きせず、環境変数で管理します。

5. Google CloudでOAuthクライアントを作成する

次に、Google Cloud 側で OAuth クライアントを作成します。

Googleログインを使うには、Google Cloud Console で以下の情報を取得する必要があります。

  • Client ID
  • Client Secret

OAuth 同意画面や OAuth クライアントの作成は、以下の公式ドキュメントが参考になります。

承認済みの JavaScript 生成元

開発環境では以下を追加しました。

http://localhost:3000

承認済みのリダイレクト URI

http://localhost:3000/users/auth/google_oauth2/callback

ポイント

  • JavaScript 生成元には オリジンのみ を指定する
  • リダイレクト URI には callback の完全URL を指定する
  • http/https、ドメイン、ポート、パスは完全一致が必要

本番環境では https:// のURLを使用する必要があるため、
開発用クライアントと本番用クライアントは分けて管理するのがおすすめです。

6. 環境変数を設定する

取得した Client ID / Client Secret は環境変数に設定します。

.env に以下を追加します。

env
GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxxxx

Docker を使っている場合、環境変数を変更したあとにコンテナを再作成しないと反映されないことがあります。
その場合は以下を実行します。

bash
docker compose down
docker compose up -d --build

7. callback用のコントローラーを作成する

Google認証後に返ってきた情報を受け取るため、callback用のコントローラーを作成します。

bash
app/controllers/users/omniauth_callbacks_controller.rb
rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def google_oauth2
    auth = request.env["omniauth.auth"]

    user = User.find_by(provider: auth.provider, uid: auth.uid)

    if user.nil?
      user = User.find_or_initialize_by(email: auth.info.email)
      user.provider = auth.provider
      user.uid = auth.uid
      user.name ||= auth.info.name
      user.password = Devise.friendly_token[0, 20] if user.encrypted_password.blank?
      user.skip_confirmation! if user.respond_to?(:skip_confirmation!)
      user.save!
    end

    sign_in_and_redirect user, event: :authentication
    set_flash_message(:notice, :success, kind: "Google") if is_navigational_format?
  end

  def failure
    redirect_to new_user_session_path, alert: "Googleログインに失敗しました。"
  end
end

何をしているか

  • request.env["omniauth.auth"] で Google から返ってきた認証情報を取得
  • provider と uid で既存ユーザーを探す
  • 見つからなければ email で既存ユーザーを探す
  • 該当ユーザーがいなければ新規作成する
  • sign_in_and_redirect でログイン処理を行う

既存のメールアドレスと一致するユーザーがいた場合は、そのユーザーに Google ログイン情報を紐付けるようにしています。

8. routesを設定する

次に、Google認証後のcallbackを受け取るために routes.rb を設定します。

config/routes.rb の devise_for :users に、OmniAuth の callback controller を追加します。

rb
devise_for :users, controllers: {
  omniauth_callbacks: "users/omniauth_callbacks"
}

何をしているか

•	devise_for :users

Devise のユーザー認証用ルーティングを定義しています。

•	omniauth_callbacks: "users/omniauth_callbacks"

Google認証後の callback を Users::OmniauthCallbacksController で受け取る設定です。

ポイント

この設定を追加すると、Googleログイン用のルートが作成されます。

例えば以下のようなルートが生えます。

•	/users/auth/google_oauth2
•	/users/auth/google_oauth2/callback

ルートが正しく追加されているかは、以下のコマンドで確認できます。

bash
bin/rails routes | grep google

9. ログイン画面にGoogleログインボタンを追加する

次に、ログイン画面から Google 認証を開始できるように、Googleログインボタンを追加します。

今回は app/views/devise/sessions/new.html.erb に追加しました。

erb
<%= button_to user_google_oauth2_omniauth_authorize_path,
      method: :post,
      data: { turbo: false },
      form: { class: "w-full" },
      class: "w-full inline-flex items-center justify-center gap-2 rounded-md border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-700 shadow-sm hover:bg-slate-50 hover:border-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 transition" do %>
  <svg class="h-4 w-4" viewBox="0 0 48 48" aria-hidden="true">
    <path fill="#FFC107" d="M43.611 20.083H42V20H24v8h11.303C33.654 32.657 29.195 36 24 36c-6.627 0-12-5.373-12-12s5.373-12 12-12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.27 4 24 4 12.955 4 4 12.955 4 24s8.955 20 20 20 20-8.955 20-20c0-1.341-.138-2.65-.389-3.917z"/>
    <path fill="#FF3D00" d="M6.306 14.691l6.571 4.819C14.655 15.108 18.961 12 24 12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.27 4 24 4c-7.682 0-14.347 4.337-17.694 10.691z"/>
    <path fill="#4CAF50" d="M24 44c5.17 0 9.86-1.977 13.409-5.193l-6.19-5.238C29.145 35.091 26.715 36 24 36c-5.175 0-9.624-3.332-11.283-7.946l-6.522 5.025C9.5 39.556 16.227 44 24 44z"/>
    <path fill="#1976D2" d="M43.611 20.083H42V20H24v8h11.303a12.046 12.046 0 0 1-4.084 5.569l.003-.002 6.19 5.238C37.01 39.171 44 34 44 24c0-1.341-.138-2.65-.389-3.917z"/>
  </svg>
  <span>Googleでログイン</span>
<% end %>

何をしているか

•	user_google_oauth2_omniauth_authorize_path

Google認証開始用のルートです。

•	method: :post

POST で認証を開始します。

•	data: { turbo: false }

Turbo の影響を避けるために指定しています。

•	form: { class: "w-full" }

button_to が生成する form に幅を持たせています。

10. 新規登録画面にもGoogleログインボタンを追加する

ログイン画面だけでなく、新規登録画面にも Googleログインボタンを追加しました。

Google認証では、既存ユーザーならログイン、未登録ユーザーなら新規作成という流れになるため、新規登録画面にも同じ導線を置いています。

11. 動作確認をする

ここまで設定できたら、実際に Googleログインが動くか確認します。

今回は以下の流れで確認しました。

確認したこと

  • ログイン画面から Googleログインできるか
  • 新規登録画面から Googleログインできるか
  • 既存ユーザーに provider / uid が保存されるか
  • 未登録ユーザーが新規作成されるか
  • 2回目以降も同じユーザーとしてログインできるか

まとめ

今回の実装で、Devise を使った Rails アプリに Googleログイン機能を追加できました。

手順をまとめると以下です。

  • gemを追加する
  • usersテーブルにカラムを追加する(provider, uid)
  • Userモデルを omniauthable に対応させる
  • DeviseにGoogle OAuthの設定を追加する
  • Google CloudでOAuthクライアントを作成する
  • callback用のコントローラーを作成する
  • routesを設定する
  • ログイン画面 / 新規登録画面にGoogleログインボタンを追加する
  • 動作確認をする

既存ユーザーへの紐付けも含めて実装できたので、通常ログインと Googleログインを両立できる形になりました。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?