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

Google認証の導入について(devise+Omniauth)

Posted at

はじめに

さまざまな記事を拝見して、Google認証は設定できましたが、備忘録として今回記事を作成いたします。基本的には公式を参考に作成していますが、書かれていることをそのまま記述するのではなく、調べて理解したことを記述しております。間違い等ございましたら、教えていただきますようお願いいたします。少しでもお役に立てれば幸いです。

現状

技術スタック

OS: macOS Sonoma 14.6.1
Docker: 24.0.2
Docker Compose: v2.18.1
Ruby: 3.1.4
Rails: 7.0.8.1
データベース: PostgreSQL 12.18
CSSフレームワーク: Bootstrap 5
CircleCI: 継続的インテグレーション(CI/CD)を導入

  • Gemのdeviseについては導入していましたが、既にUserモデルを作成してしまっていたので、こちらを参考に設定しました。

上記の記事で一点私と異なった点が、rails db:migrateでエラーが起こったとなっていたが、私の場合は以下のコマンドでエラーが出ず実行できた。

 docker-compose exec web rails db:migrate

手順

1 Google認証情報の設定

これはGoogleの開発者用サイトで、Googleログインを使用するために設定するものです。そのために、私は以下のサイトを参考にしました。

こちらのサイトから設定を行い、APIキーを取得してください。

2 Gemのインストール及びカラムの追加

下記のGemを追加してください。

Gemfile
gem 'devise'
gem 'omniauth-google-oauth2'
gem 'omniauth-rails_csrf_protection'

以下の2つのカラムを追加してください。

ターミナル
rails g migration AddOmniauthToUsers provider:string uid:string
docker-compose exec コンテナ名 rails db:migrate

これらのカラムはproviderはどの外部認証活用したかを保存し、uidはそれらのサービスでのIDを保存しておく。それらによって、すでにデータがあればログインでき、なければ新規ユーザーとしてデータを保存する。

3 プロバイダーの設定

先ほど作成したGoogleログインを使用するために作成したAPIキーを活用して、紐づける役割だと思います、、、、、(自信がないので違っていれば教えてください)

config/initializers/devise.rb
config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET']

4 モデルに外部認証の設定を追加

app/models/user.rb
devise :omniauthable, omniauth_providers: [:google_oauth2]

上記の設定は、deviseにomniauthableを追加して、外部認証を有効にします。omniauth_providers: [:google_oauth2]はどの外部認証サービスを活用するかを明確にします。今回はGoogleログインを使用する設定です。

これにより、config/routes.rbにてevise_for :usersを記述することで、google関連の以下のルーティングも自動作成される。

ターミナル
user_google_oauth2_omniauth_authorize GET|POST /users/auth/google_oauth2(.:format) devise/omniauth_callbacks#passthru
user_google_oauth2_omniauth_callback  GET|POST /users/auth/google_oauth2/callback(.:format) devise/omniauth_callbacks#google_oauth2

5 ルーティングの定義

ログアウトのルーティングには名前付きルートヘルパーを活用して、link_toにてmethod: :deleteを省略することもできますが、今回はdevise_scopeにてそれらの設定は行いません。

config/routes.rb
devise_for :users, controllers: {
    omniauth_callbacks: 'users/omniauth_callbacks'
}

devise_for :usersの部分では、deviseが提供する認証機能のルートを自動生成してくれます。ですので、先ほどのモデルの設定があることで必要なルートが作成されます。
Googleからの認証結果が、/users/auth/google_oauth2/callbackに送られるタイミングでdeviseがそのリクエストを検知するらしい。もう少し簡単に言うと、ルートにリクエストが来たタイミングで、controllers:が参照されるらしいです。

ここで疑問に思ったことは、ルートにリクエストが来たタイミングならログインボタンを押したタイミングでも参照されるのでは?と疑問に思いました。結論、そのタイミングは参照されない様子。ログインボタンを押したタイミングはユーザーをリダイレクトするので、リクエストされるのはユーザーが認証を完了してGoogleが認証結果をアプリのURLに送られた時のみ。つまり、アプリからGoogleにリクエストする時に'controllers'は参照されずに、Googleからアプリにリクエストする時に参照されるらしいです。難しいですが、少し理解ができました。

6 コントローラーの設定

まずapp/controllers/users/omniauth_callbacks_controller.rbを作成します。

ターミナル
bin/rails g controller users::omniauth_callbacks 

作成できたら、omniauth_callbacks_controller.rbを編集していきます。

users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  skip_before_action :verify_authenticity_token, only: :google_oauth2

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

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

  def failure
    redirect_to root_path
  end
end
  skip_before_action :verify_authenticity_token, only: :google_oauth2

上記の記述は、railsはCSRFトークンを使用して、フォーム送信やログインリクエストが正しいかチェックしているらしい。ただし、外部認証だとCSRFトークンが含まれていないため、google_oauth2のCSRFトークンのチェックを無効にしているらしいです。

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

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

上記の記述は認証結果を処理するための記述です。リクエストが送られたら上記のメソッドが呼び出されます。User.from_omniauthメソッドは認証情報を検索し、見つからなければ作成します。なので、基本的にはif @user.persisted?ではtrueになるはずですが、Googleからの情報にメールアドレスがないなどの場合には、バリデーションエラーとなって、elseの処理になります。

7 モデルの追記

先ほどのUser.from_omniauthメソッドを追記して、ユーザーの情報を取得・保存する処理を記述する。

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

8 ログイン・ログアウトボタンの設置

<%= button_to "グーグルでのログイン", user_google_oauth2_omniauth_authorize_path, method: :post, data: { turbo: false } %>

link_toで実装した場合、エラーが出てしまったので、一旦はこちらの記述で実装しております。

おわりに

今回のGoogle認証は初学者の私にとってかなり難しかったですが、色々なコードを見て学ぶ勉強になりました。今はGoogle認証だけですが、時間があれば他の認証も追加していきたいと思います。
以下、参考にさせていただいた記事等を載せておきます。最後まで閲覧いただき誠にありがとうございました。

↑公式とこちらのサイトを見ながら実装いたしました。大変お世話になりました。

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