0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

(ローカル環境)Rails における `devise + Omniauth` の Google 認証の導入メモ

Posted at

はじめに

  • devise および OmniAuth に関連する資料は有志の方々によって作成されていますが、いざ自分が導入するとかなり時間を要したため自分のためにも記事にしました。尚、ご指摘箇所がございましたらご教授いただけますと幸いです。
  • 随時更新する予定です

現状および前提条件など

現状

  • 上の記事の通り、「devise は導入した」まで作業を進行したことを前提としている
    • deviseによって生成される devise モデルではなく、既に作成していた User モデルを利用した形

前提条件など

  • 開発環境について以下に列挙

    • Windows11 Home 24H2
    • Ubuntsu
    • Docker
    • VScode
    • Rails7.2.1
    • devise4.9
  • Devise では users テーブルでユーザー情報を管理しているため、モデルは User になっています

  • 当記事は公式の手順書通りに実装していき一部変更を加えながら作業した結果実装できたのでベースは公式の手順書です


1. Google 認証利用に際しての認証情報の設定および取得(2024/10/22時点での操作)

Google 認証を使用する場合、"omniauth-google-oauth2" の手順にある通り『"Google クライアント ID""Google クライアントシークレット" という API キーを取得』する必要があるため、それら必要な情報を取得するのが目的

Get your API key at: https://code.google.com/apis/console/ Note the Client ID and the Client Secret.

ザックリ説明としては『認証サーバー(Google 側) に対して、どのクライアント(Google認証を利用したい Web アプリ側) が Google 認証を利用するか』を URI など含めて設定する

 
*以下の記事が完成されすぎており大変参考になります。よって当記事では割愛しております。ご了承ください。 → よろしければこちらも併せてご一読ください

2. Gem のインストール

  • 以下のような Gem を追加しました
    • omniauthは不要だったかもしれません
gem "devise", "~> 4.9"         # 追加
gem 'omniauth'             # 追加(もしかしたら不要?)
gem 'omniauth-rails_csrf_protection' # 追加
gem 'omniauth-google-oauth2'      # 追加


group :development, :test do
    # ---(中略)---
    gem 'dotenv' # 追加
end
(メモ) gem 'omniauth' が不要とかもしれない理由 1. インストールしていなくても動作して方の記事が散見されたため 1. deviseの手順書(https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview)にも対象のプロバイダーの OmniAuth ジェムを導入するだけで omniauth を導入しているかは不明なため

3. アカウントを管理するテーブルにカラムを追加

  • 以下のコマンドの通り、2 つのカラムを追加する
User モデルへのカラム追加
rails g migration AddOmniauthToUsers provider:string uid:string
rake db:migrate

4. プロバイダーの指定

  • 以下のように環境変数を受け取るような形でプロバイダーを宣言
config/initializers/devise.rb
config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET']

他の方の記事で「カンマの後に空白を空けたらエラーになった」という旨の記述が見受けられましたが、私の場合は関係なかったです

5. モデルに omniauthable を付与

  • users がアカウント情報を管理するモデルなので User モデルに記述
  • 他に :registerable なども記述されていればそれらに追記するだけ
app/models/user.rb
devise :omniauthable, omniauth_providers: [:google_oauth2]

6. ルーティングを定義

  • 後述するコントローラーのアクションへ誘導するためのルーティングを追記
    • devise_for のスコープ内に記述する点は注意
  • サインアウトする際ののアクションへ誘導するためのルーティングを追記
    • コチラは devise_for のスコープには含めない
config/routes.rb
devise_for :users, controllers: { 
    # ---(中略)---
    omniauth_callbacks: 'users/omniauth_callbacks' # 追記
}
# 以下も追記
devise_scope :user do
  delete 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session
end

7. コントローラーの生成と設定

  • コントローラーを生成してアクションを記述
    • 私の場合は既に同じ名称のコントローラーが生成されていたためそれを利用しました(無い方は実行して生成)
名前空間を users にしてコマンド実行
bin/rails g controller users::omniauth_callbacks 
app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  skip_before_action :verify_authenticity_token, only: :google_oauth2

  def google_oauth2
    provider = 'google'
    @user = User.from_omniauth(request.env["omniauth.auth"])

    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication
      set_flash_message(:notice, :success, kind: "#{ provider }") if is_navigational_format?
    else
      session["devise.#{ provider }_data"] = request.env["omniauth.auth"].except(:extra)
      redirect_to new_user_registration_url
    end
  end

  def failure
    redirect_to root_path
  end
end

8. 認証を行ったユーザー情報の取得処理をモデルに追記

  • User モデルに認証を行ったユーザーの情報を取得して保存する処理を追記する
app/models/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[0, 20]
    user.name = auth.info.name
    user.image = auth.info.image
  end
end
  • この場合、画像情報も受け取って保存をしようとしているため画像保存のロジックが別に必要
  • 私の場合はユーザー名、画像が不要だったため該当箇所を削除しました
app/models/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[0, 20]
    end
  end

9. ビュー側にログイン・ログアウトのリンクを設置する

必ずリクエストメソッドは POST とする

Google 認証のログインリンクの一例
<%= button_to "グーグルでのログイン", user_google_oauth2_omniauth_authorize_path, method: :post, data: { turbo: false } %>
  • button_to によって form 要素が挿入されて明示的に記述しなくてもリクエストメソッドが POST になる
  • link_to で実装可能ですが私は上手く機能しなくて不採用にしました

 

Google 認証のログアウトリンクの一例
<%= link_to "ログアウト", destroy_user_session_path %>

個人的に躓いたポイント

  1. Devise の手順書も Facebook での認証を導入する事例を挙げていたため Google の場合だとどうなるか分からなかった
    • 基本は facebook の箇所を google-oauth2 に置き換えるだけで良いという具合で安心した
  2. ジェムの dotenv を入れていなかったため環境変数を格納していた .env を読み込めていなかった
    • ローカルで Google 認証に必要となる API キーを格納するには必須だった
    • 本番環境では不要なファイルなので .gitignore の対称である
    • dotenv の理解が無かったため「credentials の編集」を行ったがこれも変化なしだった
      • おそらくこちらが本番環境には必須と思われる

不明点

  • この場合 omniauth の gem 必要だったのか
  • なぜか link_to で実装可能ですが私の場合は上手く機能しませんでした
    • 以下のように POST メソッドを指定して、Turbo もオフにしたのですがダメでした
link_to の場合
<%= link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path, method: :post, data: { turbo: false } %>

参考資料

※リンクカードの方が分かりやすいのでリンクカードにしております。非常に間延びしておりますがご了承ください。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?