CognitoユーザープールのホストされたUIでサインインページを作成する
Cognitoを使用してサインインページを作成します。
CognitoはAWSが提供する認証系サービスです。
Amazon Cognito は、ウェブおよびモバイルアプリの認証、承認、およびユーザー管理機能を提供します。ユーザーは、ユーザー名とパスワードを使用して直接サインインするか、Facebook、Amazon、Google、Apple などのサードパーティーを通じてサインインできます。
Amazon Cognito とは
今回はCognitoユーザープールのホストされたUIを使用して、サインインページを作成します。
Amazon Cognito でホストされる UI は、OAuth 2.0 準拠の認証サーバーを提供します。これは、登録および認証などのエンドユーザーフローのデフォルト実装を提供します。
サインアップおよびサインインでの Amazon Cognito でホストされる UI の使用
今回はAWS公式サイト「Amazon Cognito コンソールでの ホストされた UI のセットアップ」の内容に沿った環境を構築します。
構築する環境
Cognitoユーザープールを作成します。ユーザープールを使って、サインイン/サインアップ機能および同機能用ページを作成します。
サインアップ時に以下の情報を登録するように設定します。
- メールアドレス
- パスワード
- 名前 ※ usernameではない
サインインはメールアドレスおよびパスワードを使って実施することとします。
S3バケットを作成し、静的ウェブサイトホスティング機能を有効にした上で、以下の3つのHTMLファイルを設置します。
- index.html:トップページ用
- signin.html:サインイン後に表示するページ用
- signout.html:サインアウト後に表示するページ用
環境構築用のCloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートおよびHTMLファイルを配置します。
https://github.com/awstut-an-r/awstut-fa/tree/main/010
テンプレートファイルのポイント解説
今回の環境を構成するための、各テンプレートファイルのポイントを取り上げます。
ユーザープールを作成する
fa-010-cognito.yamlでCognito関係のリソースを定義します。
まずユーザープール本体を確認します。
Resources:
UserPool:
Type: AWS::Cognito::UserPool
Properties:
AutoVerifiedAttributes:
- email
UsernameAttributes:
- email
UserPoolName: !Sub ${Prefix}-UserPool
Schema:
- AttributeDataType: String
Mutable: true
Name: name
Required: true
Code language: YAML (yaml)
AutoVerifiedAttributesプロパティは、指定した属性に対して、自動的な検証を設定することができます。
Amazon Cognito は、検証コード (E メールの場合は検証リンク) を送信することで、E メールアドレスまたは携帯電話番号を自動的に検証できます。E メールアドレスの場合、コードまたはリンクは E メールメッセージで送信されます。電話番号の場合、コードは SMS テキストメッセージで送信されます。
E メールまたは電話による検証の設定
本プロパティには「email」か「phone_number」を指定できます。今回は前者を指定することで、サインアップ時に、登録したメールアドレス宛に、検証用コードが自動的に送付されるようになります。
UsernameAttributesプロパティは、ユーザー名(username)の代わりに使用する属性を指定するためのパラメータです。
UsernameAttributes
Determines whether email addresses or phone numbers can be specified as user names when a user signs up. Possible values: phone_number or email.
AWS::Cognito::UserPool UsernameAttributes
上記の通り、本プロパティには「email」か「phone_number」を指定できますが、今回は前者を指定します。このように設定することで、ユーザー名の代わりにメールアドレスを使用してサインインできるようになります。
本プロパティに関する注意点ですが、Cognitoにおいてユーザー名(username)は必須の属性とされています。
username 値は個別の属性であり、name 属性とは異なります。username はユーザーを登録するために常に必要であり、ユーザーが作成された後に変更することはできません。
ユーザープールの属性の設定 ユーザー名および優先ユーザー名
ただし今回作成するアプリのように、ユーザー名が必須ではない場合、ユーザー名の代わりにメールアドレス/電話番号を使用することができます。この場合、ユーザー名はランダムに生成されるIDが設定されます。
お客様のアプリケーションでユーザー名が不要の場合は、ユーザーにユーザー名を指定するように求める必要はありません。アプリでユーザー用の一意のユーザー名をバックグラウンドで作成できます。例えば、E メールアドレスとパスワードを登録しそれを使用してサインインするようにユーザーに求める場合は便利です。
ユーザープールの属性の設定 ユーザー名および優先ユーザー名
Schemaプロパティでサインアップ時に登録する属性を指定できます。今回は標準属性の1つであるname(usernameではない)を追加します。
なおメールアドレスやパスワードについては、UsernameAttributesプロパティで「email」をしている関係上、本プロパティでは指定不要です。
ユーザープールアプリクライアントを作成する
次にユーザープールアプリクライアントを確認します。
Resources:
UserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
AccessTokenValidity: 60 # (minutes) default value.
AllowedOAuthFlowsUserPoolClient: true
AllowedOAuthFlows:
- code
- implicit
AllowedOAuthScopes:
- aws.cognito.signin.user.admin
- email
- openid
- phone
- profile
CallbackURLs:
- !Sub "${BucketWesSiteEndpointUrl}/${SigninHtml}"
ClientName: !Sub ${Prefix}-UserPoolClient
EnableTokenRevocation: true # default value.
ExplicitAuthFlows:
- ALLOW_CUSTOM_AUTH
- ALLOW_REFRESH_TOKEN_AUTH
- ALLOW_USER_SRP_AUTH
IdTokenValidity: 60 # (minutes) default value.
LogoutURLs:
- !Sub "${BucketWesSiteEndpointUrl}/${SignoutHtml}"
PreventUserExistenceErrors: ENABLED # default value.
RefreshTokenValidity: 30 # (days) default value.
SupportedIdentityProviders:
- COGNITO
TokenValidityUnits:
AccessToken: minutes
IdToken: minutes
RefreshToken: days
UserPoolId: !Ref UserPool
Code language: YAML (yaml)
アプリクライアントを作成することで、サインアップ等のAPI操作を実行することができるようになります。
アプリは、認証されていない API 操作 (認証されたユーザーがない操作) を呼び出すための許可を持つユーザープール内のエンティティです。
ユーザープールのアプリクライアントの設定
アプリクライアントの設定は、AWS公式ページ「サインアップおよびサインインでの Amazon Cognito でホストされる UI の使用」に準じる形で設定を行います。
今回ポイントとなるパラメータはCallbackURLsおよびLogoutURLsプロパティです。それぞれサインイン後、サインアウト後のリダイレクト先のURLを指定します。
[Callback URL(s)] (コールバック URL) を入力します。コールバック URL は、ユーザーがサインインに成功したときにリダイレクトされる先を指定します。
[Sign out URL(s)] (サインアウト URL) を入力します。サインアウト URL は、ユーザーがサインアウトしたときにリダイレクトされる先を指定します。
サインアップおよびサインインでの Amazon Cognito でホストされる UI の使用
今回は後述するS3バケットに設置するHTMLファイルのURLを指定します。
ドメインを設定する
続いてドメインを確認します。
Resources:
UserPoolDomain:
Type: AWS::Cognito::UserPoolDomain
Properties:
Domain: !Ref Prefix
UserPoolId: !Ref UserPool
Code language: YAML (yaml)
ホストされたUIによるサインイン/サインアップページ用のドメインを作成する必要があります。
アプリクライアントを設定したら、サインアップおよびサインインのウェブページアドレスを設定できます。Amazon Cognito でホストされるドメインを使用して、利用可能なドメインプレフィックスを選択する、または独自のウェブアドレスをカスタムドメインとして使用することができます。
ユーザープールのドメインを設定する
今回はドメインプレフィックスを使用してドメインを設定します。Domainプロパティにプレフィックス文字列を渡します。東京リージョン(ap-northeast-1)の場合、プレフィックスを含むドメインは以下となります。
[プレフィックス].auth.ap-northeast-1.amazoncognito.com
またホストされるUIによるサインイン/サインアウトページ用のURLは以下になります。
- サインインページ用URL
- https://[プレフィックス].auth.ap-northeast-1.amazoncognito.com/login?response_type=code&client_id=[アプリクライアントID]&redirect_uri=[サインイン後のリダイレクト先URL]
- サインアウトページ用URL
- https://[プレフィックス].auth.ap-northeast-1.amazoncognito.com/logout?response_type=code&client_id=[アプリクライアントID]&logout_uri=[サインアウト後のリダイレクト先URL]
なおサインイン/サインアウト先として指定できるURLには制限があり、「https」で開始するURLである必要がありますのでご注意ください。
S3静的ウェブサイトホスティング機能でサインイン/サインアウト先コンテンツを用意する
fa-010-s3.yamlでS3関係のリソースを定義します。
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref Prefix
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: false
RestrictPublicBuckets: false
WebsiteConfiguration:
IndexDocument: index.html
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref Prefix
PolicyDocument:
Statement:
Action:
- s3:GetObject
Effect: Allow
Resource: !Sub "arn:aws:s3:::${S3Bucket}/*"
Principal: "*"
Code language: YAML (yaml)
サインインおよびサインアウト後に表示するコンテンツを用意します。今回はS3が提供する静的ウェブサイトホスティング機能を使います。
Amazon S3 を使用して、静的ウェブサイトをホストできます。静的ウェブサイトでは、個々のウェブページの内容は静的コンテンツです。ほかに、クライアント側スクリプトが含まれていることもあります。
Amazon S3 を使用して静的ウェブサイトをホスティングする
詳細は以下のページをご確認ください。
なお同機能を使って公開するコンテンツは、2種類のエンドポイント(ウェブサイトエンドポイント、RESTAPI エンドポイント)を経由してアクセスすることが可能ですが、今回はREST API エンドポイントを使用することとします。これは先述のサインイン/サインアウト先として指定するURLに関係があります。指定可能なURLの条件であるHTTPS通信が可能なエンドポイントは、REST API エンドポイントであるからです。東京リージョン(ap-northeast-1)の場合、同エンドポイントを使用してコンテンツにアクセスするためのURLは以下となります。
https://s3-ap-northeast-1.amazonaws.com/[バケット名]/[オブジェクト名]
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- S3バケットの名前:fa-010
- CognitoユーザープールのID:ap-northeast-1_Ajzqt7Te7
- Cognitoユーザープール アプリクライアントのID:5vb5gkv9rjeunvendcc1pj4089
- Cognitoユーザープール ドメインプレフィックス:fa-010
以上より、先述のホストされるUIによるサインイン/サインアウトページ用のURLは以下に定まります。
- サインインページ用URL
- https://fa-010.auth.ap-northeast-1.amazoncognito.com/login?response_type=code&client_id=5vb5gkv9rjeunvendcc1pj4089&redirect_uri=https://s3-ap-northeast-1.amazonaws.com/fa-010/signin.html
- サインアウトページ用URL
- https://fa-010.auth.ap-northeast-1.amazoncognito.com/logout?response_type=code&client_id=5vb5gkv9rjeunvendcc1pj4089&logout_uri=https://s3-ap-northeast-1.amazonaws.com/fa-010/signout.html
S3バケットにHTMLを設置する
S3バケットにHTMLを設置し、サインイン/サインアウト後のコンテンツを用意します。
先述のサインイン/サインアウト用URLをindex.htmlに記載後、AWS CLIを使用して設置します。
$ aws s3 cp ./html s3://fa-010/ \
--recursive
upload: ./html/index.html to s3://fa-010/index.html
upload: ./html/signout.html to s3://fa-010/signout.html
upload: ./html/signin.html to s3://fa-010/signin.html
Code language: Bash (bash)
ホストされたUIにアクセスする:サインアップ
準備が整いましたので、実際にホストされたUIにアクセスします。
まず以下のURLにアクセスします。
https://s3-ap-northeast-1.amazonaws.com/fa-010/index.html
するとルートページであるindex.htmlが表示されます。
「Sign In」を押下します。これはサインイン用URLへのリンクとなります。
現時点ではサインイン用のユーザーを作成していません。そのため「Sign up」を押下して、ユーザーを作成します。
Email、Passwordに加え、Nameを入力するフォームが表示されました。これはユーザープール作成時に指定した追加の属性です。今回は「awstut」という名前で登録します。
適切な値を入力後、「Sign up」を押下します。
認証コード入力フォームが表示されます。先ほど入力したメールアドレス宛にコードが送信されますので、ここに入力します。
今回は「921303」でした。
先ほどのフォームにコードを入力後、「Confirm Account」を押下することでアカウントが認証されます。
なお作成されたユーザーに関する情報は、以下のコマンドから確認することができます。
$ aws cognito-idp list-users \
--user-pool-id ap-northeast-1_Ajzqt7Te7 \
--filter "name='awstut'"
{
"Users": [
{
"Username": "29c9a15d-9749-490c-83d9-ffbfd29392a6",
"Attributes": [
{
"Name": "sub",
"Value": "29c9a15d-9749-490c-83d9-ffbfd29392a6"
},
{
"Name": "email_verified",
"Value": "true"
},
{
"Name": "name",
"Value": "awstut"
},
{
"Name": "email",
"Value": "[email-address]"
}
],
"Enabled": true,
"UserStatus": "CONFIRMED"
}
]
}
Code language: Bash (bash)
必須の属性であるusernameに、自動生成されたIDが設定されていることがわかります。
ホストされたUIにアクセスする:サインイン
上記の手続きでアカウントが作成されました。
改めてトップページ(index.html)にアクセス後、「Sign In」リンクを押下します。
メールアドレスおよびパスワードを入力後、「Sign In」を押下します。
正常にサインイン処理が行われ、リダイレクト先であるsignin.htmlが表示されました。
ホストされたUIにアクセスする:サインアウト
最後に、改めてトップページに戻り、「Sign Out」リンクを押下します。
こちらはサインアウト用URLへのリンクとなります。
正常にサインアウト処理が行われ、リダイレクト先あるsignout.htmlが表示されました。
まとめ
CognitoユーザープールおよびホストされたUIを使用することで、簡単に認証系機能を実装できることを確認しました。