LoginSignup
4
1

More than 3 years have passed since last update.

AndroidからAWS Cognitoのユーザプールをさっくり使う

Posted at

スクリーンショット 2021-01-21 8.25.15.png

サインアップやサインイン、パスワード再発行など、ユーザ管理がないアプリケーションを見かけない日はありません
とはいえ自前でバックエンドのシステムを作るのも大変...
でもAmplifyはちょっとリッチすぎる気がする...

そんな私のための備忘録です

下記のことができます

  • メールアドレス、パスワードによるサインアップ、ログアウト
  • メールアドレス認証
  • パスワード再発行

メールアドレスやパスワードはガッツリ個人情報です
その辺りの管理をAWSにお願いできるのはかなり気楽ですよねー

前準備

SES (Simple Email Service)に配信用のメールアドレスを登録する

0_SESにメールアドレスを登録し、送られたURLをクリックしてVerifyする.PNG

AWSのSESに、認証コードを送信する用のメールアドレスを登録、認証しておきます
登録したメールアドレスに確認用のURLが届くのでクリックすると認証できます
Verification Statusが"verified"になっていれば使用可能です

1_登録したメールアドレスでテストメールを送信する.PNG

"Send a Test Email"ボタンで自分自身にテストメールを送り、無事受信できればOKです

Cognitoにユーザプールを作成する

2_CognitoUserPoolを作成する.PNG

AWS Cognitoのダッシュボードにアクセスし、UserPoolを作成します
送信元のEメールアドレスに、先ほど認証したメールアドレスを登録し、Amazon SESによるEメール配信を”はい”に指定します

3_アプリクライアントの認証はとりあえずこんな漢字.PNG

アプリクライアント側の設定はこんな感じです

Androidクライアントを実装する

依存関係

依存関係に、下記を追加します

build.gradle
implementation 'com.amazonaws:aws-android-sdk-cognitoidentityprovider:2.19.0'

いよいよ実装

初期化

val userPoolId = "ap-northeast-1_xxxxxxxx"
val clientId = "yyyyyyyyyyyyy"
val clientSecret = "zzzzzzzzzzzzzz"
val userPool = CognitoUserPool(context, userPoolId, clientId, clientSecret, Regions.AP_NORTHEAST_1)

先ほど作成したCognitoUserPoolのUserPoolId, ClientId, ClientSecretを使ってインスタンスを作成します
以後、このuserPoolインスタンスを使って各種アクセスをおこないます

サインアップ

サインアップをするには2つのメソッドが必要です

  1. signUpInBackground : userPoolにユーザを作成する
  2. confirmSignUpInBackground : cognitoユーザを認証する

まずはsignUpInBackgroundです
この時点でuserPoolにユーザが追加され、本人確認用コードが送信されます
ただしUNCONFIRMEDの状態で何もできません

fun signUp(username: String, 
           password: String,
           successCallback: () -> Unit, 
           failureCallback: (exception: Exception?) -> Unit
) {
    val userAttributes = CognitoUserAttributes()

    userPool.signUpInBackground(username, password, userAttributes, null,
            object : SignUpHandler {
                override fun onSuccess(user: CognitoUser?, signUpResult: SignUpResult?) {
                    successCallback()
                }

                override fun onFailure(exception: java.lang.Exception?) {
                    failureCallback(exception)
                }

            }
    )
} 

このままだとサインインも何もできないので、続いて本人確認をする必要があります
送信された認証用コードを使ってconfirmSignUpInBackgroundを呼ぶとCONFIRMED状態になります

fun confirmSignUp(username: String, 
                  verifyCode: String,
                  successCallback: () -> Unit,
                  failureCallback: (exception: Exception?) -> Unit
) {
    userPool.getUser(username).confirmSignUpInBackground(verifyCode, false,
        object : GenericHandler {
            override fun onSuccess() {
                successCallback()
            }

            override fun onFailure(exception: Exception?) {
                failureCallback(exception)
            }
        })
}

サインイン

サインインにはgetSessionInBackgroundを使用します
一度サインインに成功すると端末内にセッションとして状態が保持されるようです
今回は2段階認証を有効化していないので、getMFACodeなどはコールされない(はず)

fun signIn(username: String, 
           password: String,
           successCallback: () -> Unit,
           failureCallback: (exception: Exception?) -> Unit
) {
    userPool.getUser(username).getSessionInBackground(
        object : AuthenticationHandler {
            override fun onSuccess(userSession: CognitoUserSession?, newDevice: CognitoDevice?) {
                successCallback()
            }
            override fun getAuthenticationDetails(
                authenticationContinuation: AuthenticationContinuation?,
                userId: String?
            ) {
                val authenticationDetails = AuthenticationDetails(userId, password, null)
                authenticationContinuation!!.setAuthenticationDetails(authenticationDetails)
                authenticationContinuation.continueTask()
            }

            override fun getMFACode(continuation: MultiFactorAuthenticationContinuation?) {
                /* should not be called */
            }

            override fun authenticationChallenge(continuation: ChallengeContinuation?) {
                /* should not be called */
            }

            override fun onFailure(exception: Exception?) {
                failureCallback(exception)
            }
        })
}

パスワード再発行

パスワードの再発行にはforgotPasswordInBackGroundを使います
実行するとパスワード再発行用の認証コードがメールアドレスに送られ、getResetCodeコールバックが返ってきます
その時に一緒に得られるcontinuationを使って、新しい認証コードとパスワードを設定すると完了です

認証周りはサインアップと似たようなものかと思いきや、少し違いますね

fun forgotPassword(username: String,
                   successCallback: () -> Unit,
                   verifyCallback: () -> Unit,
                   failureCallback: (exception: Exception?) -> Unit
) {
    userPool.getUser(username).forgotPasswordInBackground(
        object: ForgotPasswordHandler {
            override fun onSuccess() {
                successCallback()
            }

            override fun getResetCode(forgotPasswordContinuation: ForgotPasswordContinuation?) {
                continuation = forgotPasswordContinuation
                verifyCallback()
            }

            override fun onFailure(exception: Exception?) {
                failureCallback(exception)
            }
        })
}

fun verifyPasswordReset(password: String, verifyCode: String) {
    continuation?.apply {
        setPassword(password)
        setVerificationCode(verifyCode)
        continueTask()
    }
}

まとめ

cognito側の仕様にはあまり触れていませんが、これでさっくり使えます!

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1