PHPで Amazon Cognito を使用した認証機能の導入 その3:SMS認証

  • HOME
  • SPI ブログ
  • PHPで Amazon Cognito を使用した認証機能の導入 その3:SMS認証

PHPで Amazon Cognito を使用した認証機能の導入 その3:SMS認証

ユーザー認証システムとしてAmazon Cognitoを利用する場合に、
JavaScriptやPythonを使わずあえて『PHP』でやりたいという方のための覚書になります。

※本記事は2023年4月のAWSコンソールを元に書かれています。
 それ以降は画面が変更されている可能性があります。

使用ツールは「AWS SDK for PHP – Version 3」
Github

フロントはCakePHP4で作成していますがお好みで。

前回一般的な認証の設定をしたので、今回は電話番号の登録とSMS認証の設定。
前回:その2:一般的な認証

Amazon SNSの確認

CognitoでSMS認証を利用する場合はIAMの設定を行う必要があります。
ただし仕様変更などがあると記事の内容がミスリードになってしまうため、
基本的な設定はドキュメントを確認してください。
※2023年4月現在、ドキュメントと実際の操作画面が結構違います。

Amazon Cognito ユーザープール用の SMS メッセージ設定

「信頼関係」の設定

ユーザープール作成時に新規のIAMロールを作成していれば、
認証に利用しているユーザープールのIAMは↑が設定されているはずです。

IAMのコンソールで該当ロールの管理画面を開き、
タブ「信頼関係」の「信頼されたエンティティ」を
ドキュメントの内容を参考に変更してください。

テストで運用する場合、
「東京リージョン」を使用して
「日本の携帯電話」に送信する場合は
「信頼関係」の設定のみで動作するはずですが、
実際にやってみないと使えるかはわかりません。

Amazon Connectが日本の携帯電話に電話する場合ホワイトリストの登録が必要になっているため、
ひょっとしたらそれ関係の設定が必要な場合もあります。

Amazon SNSに先に電話番号を登録してテストするのも良いと思われますが、
一度登録した電話番号は24時間削除できなくなるので、
SDK経由で電話番号を登録したい場合に注意してください。

Amazon Cognitoに番号登録

前回の記事で認証に使ったユーザーに電話番号を登録、検証します。
PHP SDKの基本設定は前回の記事を参照してください。

電話番号登録

$result = $client->UpdateUserAttributes([
	'AccessToken' => 'アクセストークン',
	'UserAttributes' => [
		[
			'Name' => 'phone_number',
			'Value' => '+819011112222',
		],
	],
]);

電話番号はE164準拠で登録する必要があるため
「090-1111-2222」であれば「+819011112222」となります。

電話番号有効化

$result = $client->AdminUpdateUserAttributes([
	'UserPoolId' => $userPoolId,
	'Username' => 'ユーザー名 ※',
	'UserAttributes' => [
		[
			'Name' => 'phone_number_verified',
			'Value' => 'True',
		],
	],
]);

なお電話番号の登録と同時に設定できないようです。

ユーザーのSMS利用設定

$result = $client->AdminSetUserMFAPreference([
	'UserPoolId' => $userPoolId,
	'Username' => 'ユーザー名 ※',
	'SMSMfaSettings' => [
		'Enabled' => true,
	],
]);

実際に設定するのはAmazon SNSの疎通確認が終わってからの方が良いと思われます。

Amazon SNSに番号登録

Amazon SNS側のメソッドを使うには先にSNS用のインスタンスを立ち上げます。

require 'vendor/autoload.php';
//上記は利用する環境によりけり

use Aws\Sns\SnsClient;
use Aws\Exception\AwsException;

$snsClient = new SnsClient([
	'version' => 'latest',
	'region' => 'ap-northeast-1',
	'credentials' => [
		'key' => 'AWS-access-key',
		'secret' => 'AWS-secret-key',
	],
]);

またドキュメントは存在しますが、かなり古いものになっています。
しかしこれ以外のドキュメントがないため、仕様が変わっていないか、PHPだから放置されているかになります。

Amazon SNS SDKのドキュメント

SMSサンドボックスの登録

$result = $snsClient->createSMSSandboxPhoneNumber([
	'LanguageCode' => 'ja-JP',
	'PhoneNumber' => '+819011112222',
]);

なお既にSMS認証も済んでいる電話番号を登録しようとしても、登録されないだけでエラーになりません。
登録済みの番号を確認する場合は以下のメソッドを使用します。

登録済み番号確認

$result = $snsClient->listSMSSandboxPhoneNumbers([]);

$result[‘PhoneNumbers’]に登録番号の配列が格納されているため、
foreach等で回し[‘Status’]インデックスが「Verified」であればSMS認証済み番号です。

SMS認証がされてない番号を登録しようとした場合はSMSで認証コードが送信されるだけになります。

SMSコード認証

$result = $snsClient->verifySMSSandboxPhoneNumber([
	'OneTimePassword' => 'SMSで送られてきたコード',
	'PhoneNumber' => '+819011112222',
]);

実際の登録の流れは、これが成功した後にcognitoの有効化をすると良いと思われます。

SMS認証込みでのユーザー認証

ログイン処理(通常時と同じ)

$result = $client->AdminInitiateAuth([
	'UserPoolId' => $userPoolId,
	'AuthFlow' => 'ADMIN_USER_PASSWORD_AUTH',
	'ClientId' => $ClientId,
	'AuthParameters' => [
		'USERNAME' => 'メールアドレス',
		'PASSWORD' => 'パスワード',
	],
]);

SMS認証を設定している場合はここで「アクセストークン」と「リフレッシュトークン」が返らず、
「$result[“ChallengeName”]」に「SMS_MFA」が返却されます。
同時に$result[‘Session’]にセッションコードが登録されます。

SMSコード認証

$result = $client->RespondToAuthChallenge([
	'ChallengeName' => 'SMS_MFA',
	'ChallengeResponses' => [
		'SMS_MFA_CODE' => 'SMSで送られてきたコード',
		'USERNAME' => 'ユーザー名 ※',
	],
	'ClientId' => $ClientId,
	'Session' => 'セッションコード',
]);

こちらに成功すると「アクセストークン」と「リフレッシュトークン」が返却されます。

またこちらに成功せずに新しくログイン処理を行うと新しいSMSコードが発行されます。
この段階で以前のSMSコードは利用できなくなります。

おまけ Amazon Cognitoを利用したGoogle認証

Amazon CognitoとGoogleのOAuth2を連携させるときの覚書となります。

最初にMFAが必須のユーザープールを作成し、
その後は以下を参照すれば基本的には大丈夫です。

Amazon Cognito ユーザープールでフェデレーションアイデンティティプロバイダーとして Google を設定するにはどうすればよいですか?

現行との違いのメモとして

OAuth 同意画面を設定する
・Googleクラウドコンソールの「APIとサービス」のサイドメニューの「OAuth同意画面」
・アプリを作ってない場合は新規、既にある場合は「アプリの編集」

OAuth 2.0 クライアントの認証情報を取得する
・Googleクラウドコンソールの「APIとサービス」のサイドメニューの「認証情報」
・上の方の「+認証情報を作成」~

「https://[yourDomainPrefix].auth.[region].amazoncognito.com」
はユーザープールのコンソールのタブ「アプリケーションの統合」の「Cognito ドメイン」と同じです。

ユーザープールで Google を フェデレーティッド IdP として設定する
・左側のナビゲーションペインのリンク名は「フェデレーティッド ID」
・「3.[Google] を選択します。」は「Google+のタブ」

他は項目名を見比べながら適宜設定していきます。

ホストUIの表示

Googleの連携が完了したらログインできるかを確認しますが、ホストUIの表示方法は

ユーザープールコンソールの
タブ「アプリケーション統合」の
「アプリクライアントと分析」の
「ホストされた UI」の右にちょろっと表示されている
「ホストされた UI を表示」からとなります。

終了

以上がAmazon CognitoをPHPで設定する一連の流れとなります。
他にはAmazon SNSのアカウントをサンドボックスから脱しないとSMSがすぐ送信できなくなるなど
色々な注意はありますが適宜設定していきましょう。

最新ブログ一覧