AWSWEB

LaravelでCognitoを使用してログイン機能を作ってみた

AWS
この記事は約13分で読めます。

はじめに

インプルの矢島です。

今回はAWSのCognitoを使ってログインする機能をellaisys/aws-cognitoのライブラリを使って実装してみたらすごい簡単だったのでまとめました。

前提

  • Laravel sailで環境構築をしていること
  • Laravel ui で認証機能を作成する
  • Laravel 9を使用する
  • ellaisys/aws-cognitoを使用する
  • 2023年1月15日現在

やること

  • Laravel uiのログイン機能をカスタマイズしてログイン処理をCognitoにする
  • Cognitoで認証して、emailを元にLaravel のAuth::user()でユーザーで取得できるようになること

手順

  1. AWSマネジメントコンソールよりCognitoのユーザープールとクライアントアプリの登録
  2. Laravel uiで認証機能を構築
  3. ログイン機能をカスタマイズ

1. Cognitoの設定

ユーザープールの作成をします。
AWSのマネジメントコンソールよりCognitoを開いて設定します。

ユーザープールを新しく作成します。
プール名はお好きなお名前をご設定ください。

標準属性はemailのみとします。

このように設定します。

アプリクライアントの作成をします。

認証フローは認証用の管理APIのユーザー名パスワード認証を有効にするをチェックします。

次に検証できるようにテスト用のユーザーを作成しておきます。

2. Laravel UIでログイン画面を作成

まず、laravel sail でlaravel 9の環境構築が済んでいる必要があります。

laravel sailで環境構築方法についてはこちらから(Laravel公式)

Laravel uiとは、、、公式ライブラリでスキャフォールドを作成してくれます。あっという間に認証系の画面を作成してくれるのでめちゃくちゃ便利です。Laravel 6から切り離されて、React Vue Bootstrapからスキャフォールドを構築してくれます。今回はBootstrapを使用します。

Dockerを起動後に、Laravel Sailを起動します。

./vendor/bin/sail up

Laravel uiをインストールします。

docker-compose exec <<コンテナ名>> /bin/bash
composer require laravel/ui

//ログイン画面
php artisan ui bootstrap --auth

データベースの構築をします。

docker-compose exec <<コンテナ名>> php artisan migrate

node_modulesをインストールします。

npm install
npm run dev  //viteを動かす

この時点で、Login画面が生成されていると思います。

※この後、Cognitoでログインするために、Register画面にてCognitoにて登録したemailを使用して、新規ユーザー作成して、usersテーブルにデータがある状態にしておきましょう。

3. Laravelのログイン機能をカスタマイズ

必要なライブラリをインストール

// コンテナにはいる
composer require aws/aws-sdk-php
composer require ellaisys/aws-cognit

config/auth.phpを以下のように修正します。

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'cognito-session',
            'provider' => 'users',
        ],
    ],
//以下略

.envに以下の値を設定します。

(AWS_COGNITO_FORCE_PASSWORD_ROUTE_NAMEは、パスワード変更が必要な時に遷移するroute nameを設定します)

# AWS configurations for cloud storage
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

# AWS Cognito configurations
AWS_COGNITO_CLIENT_ID=
AWS_COGNITO_CLIENT_SECRET=
AWS_COGNITO_USER_POOL_ID=
AWS_COGNITO_REGION=
AWS_COGNITO_VERSION="latest" 

AWS_COGNITO_FORCE_PASSWORD_ROUTE_NAME=

app/Http/Controllers/Auth/LoginController.phpを以下のように修正します。

詳細はEllaisysのライブラリの概要に記載があります。

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

//追加
use Ellaisys\Cognito\Auth\AuthenticatesUsers as CognitoAuthenticatesUsers;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    // use AuthenticatesUsers;
    use CognitoAuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    public function showLoginForm() {
        return view("auth.login");
    }

        /**
         * Authenticate User
         * 
         * @throws \HttpException
         * 
         * @return mixed
         */
        public function login(\Illuminate\Http\Request $request)
        {

            //Convert request to collection
            $collection = collect($request->all());

            //Authenticate with Cognito Package Trait (with 'web' as the auth guard)
            if ($response = $this->attemptLogin($collection, 'web')) {
                if ($response===true) {
                    return redirect(route('home'))->with('success', true);
                } else if ($response===false) {
                    // If the login attempt was unsuccessful you may increment the number of attempts
                    // to login and redirect the user back to the login form. Of course, when this
                    // user surpasses their maximum number of attempts they will get locked out.
                    //
                    //$this->incrementLoginAttempts($request);
                    //
                    //$this->sendFailedLoginResponse($collection, null);
                } else {
                    return $response;
                } //End if
            } //End if

        } //Function ends
}

app/Models/User.phpを以下のように修正します。

<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
// use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Auth\Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
//追加
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;


class User extends Model implements AuthenticatableContract

{
    use Authenticatable, HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

動作確認

あらかじめ、testという名前のユーザーを作成しました。

DBに一致するemailがあり、emailとpasswordでcognito認証できた場合はログインができるようになりました!

また、Log::debug(Auth::user());でログインユーザー情報を取得することができました。

まとめ

今回のライブラリを使えば、ほとんどコードを書かずにCognitoの認証を取り入れることができました!

他にもapiのtoken認証や新規会員登録もできるのでいつか試してみようと思います〜

参考