はじめに
- 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 つのカラムを追加する
rails g migration AddOmniauthToUsers provider:string uid:string
rake db:migrate
4. プロバイダーの指定
- 以下のように環境変数を受け取るような形でプロバイダーを宣言
config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET']
他の方の記事で「カンマの後に空白を空けたらエラーになった」という旨の記述が見受けられましたが、私の場合は関係なかったです
5. モデルに omniauthable
を付与
- users がアカウント情報を管理するモデルなので User モデルに記述
- 他に
:registerable
なども記述されていればそれらに追記するだけ
devise :omniauthable, omniauth_providers: [:google_oauth2]
6. ルーティングを定義
- 後述するコントローラーのアクションへ誘導するためのルーティングを追記
-
devise_for
のスコープ内に記述する点は注意
-
- サインアウトする際ののアクションへ誘導するためのルーティングを追記
- コチラは
devise_for
のスコープには含めない
- コチラは
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. コントローラーの生成と設定
- コントローラーを生成してアクションを記述
- 私の場合は既に同じ名称のコントローラーが生成されていたためそれを利用しました(無い方は実行して生成)
bin/rails g controller users::omniauth_callbacks
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 モデルに認証を行ったユーザーの情報を取得して保存する処理を追記する
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
- この場合、画像情報も受け取って保存をしようとしているため画像保存のロジックが別に必要
- 私の場合はユーザー名、画像が不要だったため該当箇所を削除しました
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
とする
<%= button_to "グーグルでのログイン", user_google_oauth2_omniauth_authorize_path, method: :post, data: { turbo: false } %>
-
button_to
によってform
要素が挿入されて明示的に記述しなくてもリクエストメソッドがPOST
になる link_to
で実装可能ですが私は上手く機能しなくて不採用にしました
<%= link_to "ログアウト", destroy_user_session_path %>
個人的に躓いたポイント
- Devise の手順書も Facebook での認証を導入する事例を挙げていたため Google の場合だとどうなるか分からなかった
- 基本は facebook の箇所を google-oauth2 に置き換えるだけで良いという具合で安心した
- ジェムの
dotenv
を入れていなかったため環境変数を格納していた.env
を読み込めていなかった- ローカルで Google 認証に必要となる API キーを格納するには必須だった
- 本番環境では不要なファイルなので
.gitignore
の対称である -
dotenv
の理解が無かったため「credentials の編集」を行ったがこれも変化なしだった- おそらくこちらが本番環境には必須と思われる
不明点
- この場合
omniauth
の gem 必要だったのか - なぜか
link_to
で実装可能ですが私の場合は上手く機能しませんでした- 以下のように POST メソッドを指定して、Turbo もオフにしたのですがダメでした
<%= link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path, method: :post, data: { turbo: false } %>
参考資料
※リンクカードの方が分かりやすいのでリンクカードにしております。非常に間延びしておりますがご了承ください。