前提条件(環境)
2019年12月28日に試してみたものです。
Laravel 5.8
aws/aws-sdk-php 3.13
期待する動作
登録フォームにメールとパスワードを入力して送信すると、Cognitoのユーザープールに仮登録される。
そして、その際に届いたメールのリンクを辿ると、「アカウントのステータス」が「CONFIRMED」になる。
手順
- IAMで、Cognitoにアクセス可能なアクセスキー作成
- Cognito側の初期設定
- AWSのSDKをインストール
- AWSの情報を.envファイルに追加
- SDKの中にある、CognitoIdentityProviderClientクラスに用意されているsignUpメソッドを使う
1. IAMで、Cognitoにアクセスできるアクセスキー作成
割愛
2. Cognito側の初期設定
- 「ユーザープールの作成」
- 「デフォルトを確認する」
- アプリクライアントの作成
デフォルトと変えた部分は以下4つ
- ユーザーのサインインに使う項目:Eメールアドレス
- カスタム属性custom:hogeを追加
- Eメールの検証タイプを「コード」から「リンク」に変更 → Cognito ドメインの作成or自己所有ドメインの登録が必要
- アプリクライアント:「クライアントシークレットを生成」のチェックを外した
注意
- 「クライアントシークレットを生成」にチェックを入れると、SDKのCognitoIdentityProviderClientクラスの色々なメソッドの引数として、シークレットキーが必須になってくる。
- デフォルトのパスワードの強度は、強すぎるので注意
ユーザーの属性について
- 必須の標準属性と、後から追加できるカスタム属性がある。
- 標準属性は、email,genderなど17個の中から選ぶことができるが、ユーザープール作成後は変更できない。
- カスタム属性は、名前を自由に決めることができるが、名前の先頭に勝手にcustom:が付けられる。また、ユーザープール作成後に追加できるが、削除はできない。
カスタム属性について
- 試しにユーザーをプールに追加した後に、カスタム属性を追加してみたが、その場合でも、カスタム属性追加前のユーザーに、追加したカスタム属性の値を登録することができた。
-
ユーザープール作成後にカスタム属性を追加した場合、デフォルトのアプリクライアントでは、カスタム属性の読み込み権限や書き込み権限が付与されていない。
アプリクライアント画面の「属性の読み込みおよび書き込みアクセス権限を設定する」で変更できる。
3. AWSのSDKをインストール
これで、CognitoのAPIにアクセスできるメソッド等をvendor内にインストールできる
$ composer require aws/aws-sdk-php
4. AWSの情報を.envファイルに追加
.env
# AWS(IAM)
AWS_ACCESS_KEY_ID==(IAMユーザーのアクセスキーID)
AWS_SECRET_ACCESS_KEY=(IAMユーザーのシークレットアクセスキー)
# AWS(Cognito)
AWS_DEFAULT_REGION=(ユーザープールを作成したリージョン)
AWS_COGNITO_VERSION=2016-04-18
AWS_COGNITO_USER_POOL_ID=(プールID)
AWS_COGNITO_APP_CLIENT_ID=(アプリクライアントID)
5.CognitoIdentityProviderClientクラスのsignUpメソッドを使う
- CognitoのAPIにアクセスするためのクライアントを実装
- 下記URLに、CognitoIdentityProviderClientクラスのメソッドの一覧があり、それぞれ引数や返り値等が書かれている。
- signUpメソッドの必須の引数は3つ(ClientId、Password、Username)。必須の標準属性を設定した場合には、そのUserAttributesも必須。「クライアントシークレットを生成」にチェックを入れている場合、SecretHashも必須
app/Cognito/CognitoClient.php
<?php
namespace App\Cognito;
// SDKの中から使うクラス
use Aws\CognitoIdentityProvider\CognitoIdentityProviderClient;
use Aws\CognitoIdentityProvider\Exception\CognitoIdentityProviderException;
class CognitoClient
{
protected $client;
protected $clientId;
protected $poolId;
public function __construct(CognitoIdentityProviderClient $client, $clientId, $poolId)
{
$this->client = $client;
$this->clientId = $clientId;
$this->poolId = $poolId;
}
public function register($email, $password, array $attributes = [])
{
$attributes['email'] = $email;
try {
//CognitoIdentityProviderClientクラスのsignUpメソッド
$response = $this->client->signUp([
'ClientId' => $this->clientId,
'Password' => $password,
'UserAttributes' => $this->formatAttributes($attributes),
'Username' => $email,
]);
} catch (CognitoIdentityProviderException $e) {
throw $e;
}
return;
}
protected function formatAttributes(array $attributes)
{
$userAttributes = [];
foreach ($attributes as $key => $value) {
$userAttributes[] = [
'Name' => $key,
'Value' => $value,
];
}
return $userAttributes;
}
}
6 その他のソースコード
あえてGuardは使わず、できるだけシンプルにしました。
ルーティング
routes/web.php
// 登録フォーム
Route::get('/register', "RegisterController@registerForm")->name('authRegister');
Route::post('/register', "RegisterController@temporaryRegister");
ビュー1つ
resources/views/auth/register_form.blade.php
{{-- フラッシュメッセージ --}}
@if (session('temporary_register'))
<div class="alert alert-success">
{{ session('temporary_register') }}
</div>
@endif
{{-- 登録フォーム --}}
<div>
<form action="{{ route('authRegister') }}" method="post">
@csrf
<input type="email" name="email">
<input type="password" name="password">
<input type="submit" value="新規登録する">
</form>
</div>
Cognito用のServiceProvider
app/Providers/CognitoAuthServiceProvider.php
<?php
namespace App\Providers;
use App\Cognito\CognitoClient;
use Aws\CognitoIdentityProvider\CognitoIdentityProviderClient;
use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider;
class CognitoAuthServiceProvider extends ServiceProvider
{
public function boot()
{
// .envファイルに書いた認証情報と、CognitoClientの結合
$this->app->singleton(CognitoClient::class, function (Application $app) {
$config = [
'region' => env('AWS_DEFAULT_REGION'),
'version' => env('AWS_COGNITO_VERSION'),
];
return new CognitoClient(
new CognitoIdentityProviderClient($config),
env('AWS_COGNITO_APP_CLIENT_ID'),
env('AWS_COGNITO_USER_POOL_ID')
);
});
}
}
作成したServiceProvierの登録を忘れないように!
app/config/app.php
// 中略
'providers' => [
// 中略
App\Providers\CognitoAuthServiceProvider::class, // <- 追加
];
Controller
app/Http/Controllers/RegisterController.php
<?php
namespace App\Http\Controllers;
use App\Cognito\CognitoClient;
use Illuminate\Http\Request;
class RegisterController extends Controller
{
public function registerForm()
{
return view("auth.register_form");
}
public function temporaryRegister(Request $request)
{
// 属性
$attributes = ['custom:hoge' => "テスト"];
// CognitoClientクラスに書いたregisterメソッドを使う
app()->make(CognitoClient::class)->register($request->email, $request->password, $attributes);
return redirect()->route('authRegister')->with('temporary_register', 'まだ仮登録です。メールに記載されたリンクにアクセスして下さい');
}
}
その他:パスワードリセット・変更等のメソッド
メソッド | |
---|---|
パスワードリセット | ForgotPassword |
パスワード変更 | ChangePassword |
属性の変更 | UpdateUserAttributes |
退会 | DeleteUser |
これらは全て、AccessTokenが必須の引数となっている。
AccessTokenは、InitiateAuth(又はAdminInitiateAuth)メソッドの返り値として取得できる。
参考にさせて頂いた記事
Laravel + AWS Cognito での認証機能の実装【ユーザー新規登録編】
[Laravelのユーザ認証をAmazon Cognitoで行う方法]
(https://qiita.com/suzumurakk/items/efe4543cf0df2cd31659)