0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel】CognitoとGoogle認証を連携して”ナウい”ログイン機能を実装してみた

Last updated at Posted at 2024-09-29

こんにちは!

バックエンドエンジニアからフルスタックエンジニアにメガ進化したいすぎちゃんです! :cat:

読者の皆さんはポートフォリオを作る中でこんな悩みに直面したことはないでしょうか?

ポートフォリオサイトにログイン機能を実装してみたけど、何かイケてる感じが足りない...

ユーザーがログインするまでの手間を減らして、もっとスムーズに認証できないかな?

せっかくポートフォリオを作るなら、もっとオシャレでスマートなログイン機能を搭載して、インパクトを与えたいですよね。

そこで今回は、AWSのCognitoを使いながら、LaravelでGoogle認証を組み合わせて、"カッコいい"認証機能を作る方法をご紹介します!

Googleアカウントを使えば、ユーザー名やパスワードを入力する必要がなくなり、ワンクリックでログイン完了。ユーザーのストレスも減り、操作感もグッと向上すること間違いありません! :fire:

成果物

画面収録+2024-09-28+22.07.27_out.gif

こちらが今回の記事の成果物となります!

実際にGoogle認証はchatGPTDropboxなどの大手のサイトで導入されています。

これまで普通のメールアドレス・パスワード形式でログイン画面を作っていた方も、ぜひ今回の内容を参考にして、ポートフォリオの印象を一気にランクアップさせてみてください!

事前準備

LaravelでGoogle認証を実装する前に、以下3の項目について事前に設定しておいてください :thumbsup:

  1. Cognitoのユーザープール、ユーザー情報保管用のテーブルを用意
  2. Google認証をCognitoと連携
  3. route/web.phpに認証関連のルーティングを追加

1. Cognitoのユーザープール、ユーザー情報保管用のテーブルを用意

2. Google認証をCognitoと連携

「ホストされたUIを編集」の画面で「許可されているコールバックURL」を以下のように設定しておきましょう。

http://<自身のアプリケーションのドメイン>/auth/google/callback

ローカルホストで開発する場合はhttp://localhost:8080/auth/google/callbackとします。

3. route/web.phpに認証関連のルーティングを追加

routes/web.php

web.php
Route::get('/auth/google', "App\Http\Controllers\Auth\GoogleAuthController@redirectToGoogle")->name('auth.google');
Route::get('/auth/google/callback', "App\Http\Controllers\Auth\GoogleAuthController@handleOAuthCallback")->name('auth.google.callback');
  • /auth/google
    Google認証ページにリダイレクトする処理を行います。

  • /auth/google/callback
    Google認証後に呼び出されるコールバックURLです。

上記、3つの準備が完了したらLaravelでの実装に進んでいきましょう!

実装方法

Google認証によるログインを行なった場合、裏側では以下の流れで処理が行われます。

スクリーンショット 2024-09-28 22.55.22.png

  1. 認証の要求を行う
  2. 受け取った認証コードを元にアクセストークンを要求する
  3. アクセストークンを元にユーザー情報を受け取る
  4. ユーザー情報をDBに登録

以下のコードを参考に実装を進めていきましょう :muscle:

  • GoogleAuthController.php
    GoogleのOAuth認証をトリガーし、Googleからの認証結果を処理するコントローラ。
  • GoogleAuthClient.php
    Google API との通信を行うクライアントクラス。Googleの認証ページURLの生成、認証コードからトークンを取得する処理、トークンからユーザー情報を取得する処理を担当。
  • HttpClient.php
    Google APIやCognitoなどの外部APIとのやり取りを抽象化するクライアント。
  • CreateGoogleUser.php
    Googleユーザーをデータベースに保存するサービスクラスです。既存のユーザーがいれば取得し、なければ新規に作成します。

1. 認証の要求を行う

GoogleAuthController.php
class GoogleAuthController extends Controller
{
     # ... 省略

    public function redirectToGoogle()
    {
        $url = $this->googleAuthClient->getAuthUrl();
        return redirect($url);
    }

Googleアカウントでログイン」をタップすると/auth/googleを経由し、GoogleAuthControllerクラスのredirectToGoogleメソッドが呼ばれます。

GoogleAuthClient.php
class GoogleAuthClient
{
    #... 省略

    public function getAuthUrl()
    {
        return $this->cognitoDomain.
            "/oauth2/authorize".
            "?identity_provider=Google".
            "&redirect_uri=".$this->redirectUrl.
            "&response_type=CODE".
            "&client_id=".$this->appClientId.
            "&scope=email openid";
    }

次にGoogle認証の心臓部となるGoogleAuthClientクラスのgetAuthUrlが呼び出され、/oauth/authorizeにGETリクエストを送信します。

なお、GETリクエストのURLは以下の通りです。

https://<your-cognito-domain>/oauth2/authorize?identity_provider=Google&redirect_uri=REDIRECT_URL&response_type=CODE&client_id=YOUR_CLIENT_ID&scope=email openid

<your-cognito-domain>の内容はユーザープール詳細画面の「アプリケーション統合」のタブをクリックすれば確認することができます。

スクリーンショット 2024-09-28 23.32.39.png

なお、各パラーメータの説明についても念のため記載していきます。

パラメータ 説明
identity_provider Cognitoの認証フローにおいて、指定された外部IDプロバイダー(Googleなど)を用いることを指定します。ここではGoogleと設定します。
redirect_uri 認証が成功または失敗した後に、ユーザーをリダイレクトする先のURLです。ここではhttp://<自身のアプリケーションのドメイン>/auth/google/callbackを設定します。
response_type コールバックのクエリパラメータに何を返すかを指定します。ここではCODEと指定し、この認証コードを後でアクセストークンやIDトークンに交換するために使用します。
client_id CognitoユーザープールのアプリケーションクライアントIDを指定します。CognitoやGoogleがどのアプリケーションからのリクエストであるかを認識するために使います。
scope アクセスを要求するスコープ(権限)を指定します。ユーザーのどの情報にアクセスできるかを定義するパラメータです。追加で設定をすればGoogleアカウントに紐づいているプロフ画像も参照できます

2. 受け取った認証コードを元にアクセストークンを要求する

1の手順の後、/auth/google/callbackのURLにクエリパラメータとしてcodeが付与されて返ってきます。

http://<自身のアプリケーションのドメイン>/auth/google/callback?code=ae56c4fe-f085-4449-b319-b5d21bcfaed9

この時に初めてhandleOAuthCallbackメソッドが呼び出されます。

このcodeの値を用いて、トークンエンドポイント(/oauth/token)に対してアクセストークンをリクエストします。

GoogleAuthController.php
class GoogleAuthController extends Controller
{
    private $googleAuthClient;

     #...省略

    public function handleOAuthCallback(CreateGoogleUser $createGoogleUser)
    {
        $code = request()->input('code');

        # 1.コールバックされたトークンを元にアクセストークンを取得
        $getTokenResponse = $this->googleAuthClient->getToken($code);
        
    # ...省略

GoogleAuthClient.php
class GoogleAuthClient
{
    # ... 省略

    public function getToken(string $code)
    {
        $endPoint = $this->cognitoDomain . "/oauth2/token";

        $data = [
            'grant_type'    =>  'authorization_code',
            'client_id'     =>  $this->appClientId,
            'client_secret' =>  $this->appClientSecret,
            'code'          =>  $code,
            'redirect_uri'  =>  $this->redirectUrl
        ];
        $header = 'Content-type: application/x-www-form-urlencoded';

        $response  = $this->httpClient->post($endPoint, $data, $header, false);
        return  json_decode($response, true);
    }

HttpClient.php
class HttpClient
{
    # ... 省略
    public static function post(
        string $url, 
        array $data, 
        string $header = 'Content-type: application/json; charset=UTF-8',
        bool $isJson = true
    ){
        $content = $isJson 
            ? json_encode($data)
            : http_build_query($data);

        // ストリームコンテキストオプションの設定
        $options = [
            'http' => [
                'method'  => 'POST',
                'header'  => $header,
                'content' => $content, // データを送信
                'ignore_errors' => true // エラーを無視してレスポンスを取得する
            ]
        ];

        $context = stream_context_create($options);

        return  file_get_contents($url, false, $context);
    }

以上の処理が完了すると、$getTokenResponseには以下の情報が代入されます。

スクリーンショット 2024-09-27 17.23.19.png

パラメータ 説明
id_token OpenID Connect(OIDC)フローで使用されるトークン。認証されたユーザーの情報を含むJWT(JSON Web Token)。
access_token APIにアクセスする際に用いるトークン。認可されたリソース(ユーザーのプロフィール、カレンダーなど)にアクセスするために使われる。
refresh_token 有効期限が切れたaccess_tokenを再取得するためのトークン。refresh_tokenを使うことで、再度ユーザーの許可を得ることなく新しいaccess_tokenを取得できる。
expires_in access_tokenの有効期限を示す値です。単位は秒(秒数)です。
token_type 認証ヘッダー(Authorization ヘッダー)でアクセストークンを指定する際に、どのタイプのトークンとして解釈するかを定義します。

3. アクセストークンを元にユーザー情報を受け取る

2で取得したaccess_tokenをUserInfo エンドポイント(/oauth/token)に送信します。

Authorization: Bearer <access_token>をheader情報に設定してください

Authorization: Bearer <access_token>
GoogleAuthController.php
class GoogleAuthController extends Controller
{
    # ... 省略

    public function handleOAuthCallback(CreateGoogleUser $createGoogleUser)
    {

        # ... 省略
        $getUserInfoResponse = $this->googleAuthClient->getUserInfo($getTokenResponse);

        # ... 省略
    }
GoogleAuthClient.php
class GoogleAuthClient
{
    # ... 省略

    public function getUserInfo(array $getTokenResponse)
    {
        $endPoint = $this->cognitoDomain . "/oauth2/userInfo";

        $header = 'Authorization: Bearer '. $getTokenResponse['access_token'];

        $response = $this->httpClient->get($endPoint, $header);
        return  json_decode($response, true);
    }

}
HttpClient.php
class HttpClient
{
    public static function get(
        string $url, 
        string $header = 'Content-type: application/json; charset=UTF-8'
    ){
        $options = [
            'http' => [
                'method'=> 'GET',
                'header'=> $header
            ]
        ];

        $context = stream_context_create($options);
        return file_get_contents($url, false, $context);
    }

    # ... 省略

これらの処理が完了すると、$getUserInfoResponseに以下の情報が代入されます。

スクリーンショット 2024-09-27 17.20.28.png

これでやっとCognitoにGoogleユーザーの情報が認知されました!

スクリーンショット 2024-09-29 23.17.57.png

↑ご覧の通りcognitoにもGoogleユーザーが追加されていることがわかります :smile_cat:

4. ユーザー情報をDBに登録

次に、Cognitoのユーザープールの情報をアプリケーションのDBに同期するコードを解説します!(初心者も読むことを想定しているので念のため。)

GoogleAuthController.php
class GoogleAuthController extends Controller
{
    # ... 省略

    public function handleOAuthCallback(CreateGoogleUser $createGoogleUser)
    {
        # ... 省略 
        $user = $createGoogleUser->execute($getUserInfoResponse);
        
        Auth::login($user);

        return redirect(route('home'));
    }
CreateGoogleUser.php
class CreateGoogleUser
{
    public function execute(array $getUserInfoResponse)
    {
        return (new User())->newQuery()
            ->firstOrCreate([
                'email' => $getUserInfoResponse['email'],
                'cognito_username' => $getUserInfoResponse['username']
            ]);
    }
}

Cognitoにユーザーがすでに存在するか確認し、いなければ新しく登録(サインアップ)、いれば既存ユーザーとして扱います(サインイン)。

最終的に、取得したユーザー情報をアプリケーションのDBに保存し、アプリケーション内でGoogle認証ユーザーを管理できるようにします :fire:

ユーザーをログイン状態にし、ホーム画面へリダイレクト
Auth::login($user); を使ってLaravelの認証機能を用いてユーザーをログイン状態にし、/home にリダイレクトすれば完了です!!!!!!

まとめ

ここまでお読みいただきありがとうございました。

Google認証の実装について、主要なクラスや処理を簡潔に解説しました。

この手順に従って実装を進めて、皆様のポートフォリオのランクアップの一助になれば幸いです! :thumbsup:

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?