AWS Amplify+Cognitoでユーザー認証画面をネイティブアプリで作ってみる
AWSの認証はWebUI(Hosted UI)が用意されているのでそちらで組めばサーバーレスの認証は簡単に行えますが、レイアウトを細かく変更したい時にUIをネイティブアプリで作りたくなるなと思い、ネイティブUIから繋げる方法を試してみました。
Cognitoの管理画面でWebページのUIのカスタマイズの設定もありますので、そちらで十分なら必要ないと思います。
あと、後述しますがソーシャルログインも加えたいなら素直にWebUIで実装した方が良さそうです。
Cognitoの設定などはAmplifyを使いました。
(AWSアカウント作成やIAMは事前に作成しています)
準備
AmplifyのCLIをインストールします。
npm install -g @aws-amplify/cli
手元でインストールしたバージョンはこちらです。
$ node -v
v11.12.0
$ amplify -v
4.26.0
podインストール
認証周りの実装で使用するのでAmplifyをpodインストールします。
検証時点の最新バージョンにしています。
pod 'Amplify', '1.1.0'
pod 'AmplifyPlugins/AWSCognitoAuthPlugin', '1.1.0'
podインストールします
$ pod install --repo-update
Universal Linksの設定
今回はメール認証完了後にリダイレクトURLでアプリに戻すので事前にUniversal Linksの対応をしておきます。
後で追加も可能ですが、この後のamplify add auth
の設定中にリダイレクトURLを記述するところがあるので先に準備しておく方がスムーズだと思います。
リダイレクトURLはLambdaに追加されるCustomMessage内に追加されるので間違えた場合はあとで変更も可能です。
今回はS3とCloudFrontを使って対応しましたが、記述が長くなったので別の記事に纏めました。
AWS S3+CloudFront使ってUniversal Linksでアプリを起動する
ここで作成した https://****.cloudfront.net
をリダイレクトURLとして使用していきます。
Amplify アプリケーション追加
ターミナルでプロジェクト直下まで移動し、amplify init
を実行します。
$ amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project {ここはアプリケーションの名前になるので好きなように命名してください}
? Enter a name for the environment dev
? Choose your default editor: None
? Choose the type of app that you're building ios
Using default provider awscloudformation
? Do you want to use an AWS profile? Yes
? Please choose the profile you want to use default
プロジェクトに amplify.json
、amplifyconfiguration.json
を追加しておきます。
Amplify Auth追加
amplifyでAuthを追加していきます。
Email使ってサインイン、サインアップさせたいのでマニュアルで諸々設定していきます。
Warning: you will not be able to edit these selections.
のところは後で変更できないので注意してください。
$ amplify add auth
Do you want to use the default authentication and security configuration? Manual configuration
Select the authentication/authorization services that you want to use: User Sign-Up, Sign-In, connected with AWS IAM co
ntrols (Enables per-user Storage features for images or other content, Analytics, and more)
Please provide a friendly name for your resource that will be used to label this category in the project: amplify****
Please enter a name for your identity pool. amplify****_identitypool_****
Allow unauthenticated logins? (Provides scoped down permissions that you can control via AWS IAM) No
Do you want to enable 3rd party authentication providers in your identity pool? Yes
Select the third party identity providers you want to configure for your identity pool: {選択なし}
Please provide a name for your user pool: amplify****_userpool_****
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in? Email
Do you want to add User Pool Groups? No
Do you want to add an admin queries API? No
Multifactor authentication (MFA) user login options: OFF
Email based user registration/forgot password: Enabled (Requires per-user email entry at registration)
Please specify an email verification subject: Your verification code
Please specify an email verification message: Your verification code is {####}
Do you want to override the default password policy for this User Pool? Yes
Enter the minimum password length for this User Pool: 8
Select the password character requirements for your userpool: Requires Lowercase, Requires Uppercase, Requires Numbers
Warning: you will not be able to edit these selections.
What attributes are required for signing up? Email, Name
Specify the app's refresh token expiration period (in days): 30
Do you want to specify the user attributes this app can read and write? No
Do you want to enable any of the following capabilities? Email Verification Link with Redirect
Do you want to use an OAuth flow? No
? Do you want to configure Lambda Triggers for Cognito? No
? Enter the URL that your users will be redirected to upon account confirmation: {ユニバーサルリンクが起動するURL、同じ手順で進めていれば今回はCloudFrontのURLになります}
? Enter the subject for your custom account confirmation email: アカウント確認
? Enter the body text for your custom account confirmation email (this will appear before the link URL): 下記のURLをクリックすることで、メールアドレスの認証が完了となります。
Successfully added resource amplify**** locally
成功したらマネジメントコンソールに反映させるためにamplify push
しておきましょう。
Universal Linksを動かすために必要な処理
実はこのままだとリダイレクトURLを踏んでも認証は完了しません。
メールで届くURLはS3の****verificationbucket-***
を表示して、verify.jsを実行して認証完了後に指定したURLを開こうとしていますが、そのままだと認証時にエラーになるのでローディングが回り続けて終わります。
verify.jsで発生しているエラーはNotAuthorizedException: Unable to verify secret hash for client *****
というもので
Cognitoに登録されているアプリにクライアントシークレットが設定されていることが原因です。
対応としてはCognitoのアプリにクライアントシークレットを設定していないアプリを追加して、アプリ側のjsonファイルを書き換えます。
Cognito->UserPoolのアプリクライアントの設定画面で別のアプリクライアントの追加から新規で作成します。
クライアントシークレットを生成の項目のチェックを外して作成します。
合わせてamplifyconfiguration.json と awsconfiguration.jsonの下記項目を書き換えます。
// PoolIdとRegionは変更の必要無し
// AppClientIdに新しく追加したクライアントIDに書き換え、AppClientSecretは削除する
"CognitoUserPool": {
"Default": {
"PoolId": "****",
"AppClientId": "****",
"Region": "****"
}
}
アプリ側の実装
ここからはアプリ側を実装していきます。
今回はAmplify.Authで実装していますが、AWSMobileClient.defaultでも同じように実装は可能です。
Amplify, AmplifyPluginsをインポート
import Amplify
import AmplifyPlugins
Authのセッション確認
ユーザーがCognitoのUserPoolに登録されたあとにSignInすれば、session.isSignedIn == true
になります。
_ = Amplify.Auth.fetchAuthSession(listener: { (result) in
do {
let session = try result.get()
print("fetchAuthSession succcess:\(session.isSignedIn)")
} catch {
print("fetchAuthSession error:\(error)")
}
})
Auth API実行時のコールバック受け取り
_ = Amplify.Hub.listen(to: .auth) { (payload) in
switch payload.eventName {
case HubPayload.EventName.Auth.signedIn:
// ログイン済み
case HubPayload.EventName.Auth.signedOut:
// ログアウト
case HubPayload.EventName.Auth.sessionExpired:
// セッション切れ
default: break
}
}
新規登録(サインアップ)
amplify add auth(What attributes are required for signing up?)でEmail, Nameで設定した場合の例になります。
オプションで名前、signUpの第一引数でメールアドレスを設定しないとエラーになりました。
let userAttributes = [AuthUserAttribute(.name, value: userName)]
let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
_ = Amplify.Auth.signUp(username: mailAddress, password: password, options: options) { result in
switch result {
case .success(let signUpResult):
if case let .confirmUser(deliveryDetails, _) = signUpResult.nextStep {
print("signUp: \(String(describing: deliveryDetails))")
} else {
print("signUp: complete")
}
case .failure(let error):
print("signUp error: \(error)")
}
}
ログイン(サインイン)
amplify add auth(How do you want users to be able to sign in?)でEmailを設定した場合の例になります。
_ = Amplify.Auth.signIn(username: mailAddress, password: password) { result in
switch result {
case .success(_):
print("signIn success")
case .failure(let error):
print("signIn error: \(error)")
}
}
ログアウト(サインアウト)
let options = AuthSignOutRequest.Options(globalSignOut: true)
_ = Amplify.Auth.signOut(options: options) { (result) in
switch result {
case .success:
print("signOut success")
case .failure(let error):
print("signOut error: \(error)")
}
}
処理の流れ
という流れで処理を行い、確認ができました。
ソーシャルログインの追加について
Appleの開発者ページとマネジメントコンソールでSign In with Appleの設定をすれば成功するかと思いましたが、
それだけでは上手くいきませんでした。
ネイティブアプリ側で取得したSign In with Appleのトークンを
AWSMobileClientのfederatedSignInに渡すとsignedInが返されるのですが、管理画面にはユーザー追加されずその後のCredetialの取得も失敗します。
あと、Amplify 1.1.0のバージョンでAmplify.Hub.listenでイベント監視している時にfederatedSignInを呼ぶと言うクラッシュにも遭遇しました。
こちらはすでにamplify-ios issues #640に挙げられていて、調度修正されたところだったので次のリリースあたりには解消されているかもしれません。
そもそもWebUIでないと正常に動作しない話もあるので、また時間をおいて試してみようと思います。
おわりに
Amplifyでの初期構築はすごく簡単な反面、そこから変更加えようとすると大変でした。
今回触ったことでAWSについてもっと勉強しないとなーと思えたので、いいきっかけになりました。
Author And Source
この問題について(AWS Amplify+Cognitoでユーザー認証画面をネイティブアプリで作ってみる), 我々は、より多くの情報をここで見つけました https://qiita.com/mittsu/items/b53603adffb3d86f4370著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .