社内向け管理ツールにGoogleログインを導入した話

はじめに

こんにちは!エンジニアインターンをしている湯村です。
今回、社内向け管理ツールにGoogleログインを導入したので、その話をしたいと思います。

タスクの背景

現在crispyでは、SlackやKibelaなどのツールごとにメンバーのアカウントを作成しています。
社内向け管理ツールも同様に、管理ツール用に作成したアカウントのメールアドレスとパスワードでログインしていました。

現状はそれでも問題ないのですが、今後どんどんメンバーが増えてくると、アカウントの作成・削除をそれぞれのツールで行っていると手続きが煩雑になってしまいます。
そこで、今後はメンバーのアカウントをGoogle Workspaceで一元管理し、作業を簡略化しようと考えています。

その一環として、今回は社内向け管理ツールにGoogleアカウントでログインできるように実装を行いました。

OAuth2.0

Googleログインに限らず、FacebookやTwitterなど、ソーシャルアカウントでのログインにはOAuth(オーオース)という仕組みが使われていることが多いです。
現在のバージョンはOAuth2.0です。

ソーシャルログインでは、クライアントアプリケーション(今回の場合、管理ツール)がAPIを叩いてリソースサーバー(今回の場合、Google)にアクセスし、取得したユーザーのデータを使ってクライアントアプリケーションにログインしています。

この際、APIさえ叩けば誰でもユーザーのデータが取得できる、という状態だと、悪意のあるアプリケーションがユーザーの個人情報を取得してしまう恐れがあるので、そのような事態を回避するために、アクセストークンが使われています。
Googleログインをする際、「続行するにあたり、Googleはあなたの名前、メールアドレス、言語設定、プロフィール写真を(アプリケーション名)と共有します。」という画面が出るのを見たことがあると思います。

ここでアクセスを許可すると、アプリケーションにアクセストークンが付与され、そのアクセストークンを持った状態でAPIを叩くとGoogleアカウントのユーザーデータが参照できるという仕組みになっています。

この、「アクセストークンの要求とそれに対する応答」を標準化したものがOAuth2.0です。

実装した内容

それではいよいよ実装した内容について説明していきます。
crispyの社内向け管理ツールではRailsを使用しているので、今回はomniauth-google-oauth2というgemを使用し、基本的にこちらのREADMEに従ってGCPの設定とアプリケーションのコードの追加を行いました。 github.com

GCPの設定

アプリケーションからGoogleログインのAPIを叩くことができるようにするために、GCPの設定を行います。
「APIとサービス」から「OAuth同意画面」と「認証情報」の二項目を設定します。

OAuth同意画面

アプリケーションがOAuthを使用するために必要な情報を登録します。
アプリケーション名や連絡先メールアドレスなどの必須項目を入力してください。

認証情報

認証情報を作成し、クライアントIDとクライアントシークレットを発行します。
ここで発行したIDとシークレットは、後ほどAPIが叩けるように実装をする際に必要となります。

アプリケーション側の実装

元々deviseを使用してログイン機能を実装していたので、そこに追記する形で実装していきました。

設定ファイルを記述

deviseのOmniauthableモジュールを使うと簡単に書くことができるのですが、今回は既に別のモデルでOmniauthableモジュールを使用していたため使用することができませんでした。
代わりにconfig/initializers/omniauth.rbというファイルを新しく作成し、そこに設定を記述しました。

Rails.application.config.middleware.use(OmniAuth::Builder) do
  provider(
    :google_oauth2,
    Rails.application.secrets.dig(:google, :client_id),
    Rails.application.secrets.dig(:google, :client_secret),
  )
end

client_idclient_secretには、先ほどGCPで発行されたものを設定します。

ルーティングを追加

既にログイン/ログアウトのルーティングは定義済みだったため、omniauthのコールバックのルーティングのみ追加しました。

get 'auth/google_oauth2/callback', to: 'sessions#google_oauth'

コントローラとモデルにメソッドを追加

こちらもログイン/ログアウトのメソッドは存在するため、oauthのためのメソッドのみ追加します。

# コントローラ
def google_oauth
  access_token = request.env['omniauth.auth']
  @user = User.from_omniauth(access_token)

  if @user&.persisted?
    sign_in_and_redirect(@user, event: :authentication)
  else
    session['devise.google_data'] = access_token.except('extra') # NOTE: Removing extra as it can overflow some session stores
    redirect_to new_session_path, alert: @user.errors.full_messages.join("\n")
  end
end
# モデル
class << self
  def from_omniauth(access_token)
    data = access_token.info
    User.find_by!(email: data['email'])
  end
end

あとはviewを整えて、実装完了です!

まとめ

Googleログインはgemを使うと簡単に実装できて便利なので、ぜひ導入を検討してみてください。

crispyでは、インターン生でも社員と変わらず幅広いタスクを任せてもらえます!
社内向け管理ツールの機能開発・改善だけではなく、アプリで使用するAPIの実装や、インフラ関連のタスクを行うこともあります。
開発未経験でも丁寧に教えていただけるので、安心して開発に取り組めます。
エンジニアとして成長するにはとてもいい環境だと思います!
Wantedlyで正社員・インターン共に募集しているので、覗いてみてください!