kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

Amazon Cognitoに入門してみる

f:id:kun432:20210627221207p:plain

最近Lex絡みでちょいちょいAWS Amplifyをいじっていて、Amazon Cognitoちゃんといじったことないなーと思ったので、入門してみました。

ちなみに、題材はこの辺を参考にさせてもらいました、というか、ほぼほぼ「写経」なんですが、一部古い記載もあったので、まあ一応現時点での最新ということで。

dev.classmethod.jp

目次

API GatewayでサンプルのAPIを作成

まずは、API GatewayでサンプルとなるAPIを作成します。「APIを作成」をクリック。

f:id:kun432:20210627221602p:plain

APIタイプは「REST API」にします。「インポート」をクリック。

f:id:kun432:20210627222130p:plain

「プロトコルを選択する」は「REST」、「新しい API の作成」は「APIの例」を選択すると、サンプルで用意されている「PetStore」のAPIがインポートされますので、「インポート」をクリックします。

f:id:kun432:20210627221921p:plain

APIが作成されたら「アクション」→「APIのデプロイ」をクリック。

f:id:kun432:20210627222552p:plain

デプロイのステージを適当に設定します。今回は"initial"にしました。「デプロイ」をクリック。

f:id:kun432:20210627222711p:plain

"initial"ステージがデプロイされました。左のステージ名をクリックします。

f:id:kun432:20210627223222p:plain

APIのエンドポイントがツリー形式で表示されます。/pets/{petid}のところにあるGETをクリックして表示されるURLをコピーしてください。

f:id:kun432:20210627223340p:plain

curlコマンドでURLにアクセスしてみます。その際に末尾の{petid}のところは適当な数値を設定してみてください。

$ curl https://XXXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/initial/pets/1
{
  "id": 1,
  "type": "dog",
  "price": 249.99
}
$ curl https://XXXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/initial/pets/2
{
  "id": 2,
  "type": "cat",
  "price": 124.99
}

APIが動作しているのがわかりますね。もちろん/petsのエンドポイントも動作します。

$ curl https://XXXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/initial/pets
[
  {
    "id": 1,
    "type": "dog",
    "price": 249.99
  },
  {
    "id": 2,
    "type": "cat",
    "price": 124.99
  },
  {
    "id": 3,
    "type": "fish",
    "price": 0.99
  }
]

Cognitoユーザープールの作成

ではこのAPIにCognitoで認証をかけるために、ユーザープールを作成しましょう。Cognitoのページを開いて「ユーザープールの管理」をクリック。

f:id:kun432:20210627224736p:plain

「ユーザープールを作成する」をクリックします。2箇所ありますがどちらでもよいです。

f:id:kun432:20210627224924p:plain

ユーザープール名を設定します。今回はuser_pool_testにしました。入力したら「デフォルトを確認する」をクリックします。

f:id:kun432:20210627225100p:plain

いろいろ設定が表示されますが、デフォルトのまま「プールの作成」をクリックします。

f:id:kun432:20210627225309p:plain

「ユーザープールは正常に作成されました」と表示されればOKです。上の方に表示されている「プールID」を後で使いますので、メモしておきましょう。

f:id:kun432:20210627225510p:plain

次にアプリクライアントを作成します。左のメニューから「アプリクライアント」をクリック。

f:id:kun432:20210627225745p:plain

「アプリクライアントを追加」をクリックします。

f:id:kun432:20210627225904p:plain

アプリクライアント名は適当に設定します。今回はcognito-cliとしました。「認証用の管理APIのユーザ名パスワード認証を有効にする(ALLOW_ADMIN_USER_PASSWORD_AUTH)」にチェックを入れ、以下のチェックは外します。

  • クライアントシークレットを作成
  • Lambdaトリガーベースのカスタム認証を有効にする (ALLOW_CUSTOM_AUTH)
  • SRP (セキュアリモートパスワード) プロトコルベースの認証を有効にする (ALLOW_USER_SRP_AUTH)

そして「アプリクライアントの作成」をクリックします。

f:id:kun432:20210627230549p:plain

アプリクライアントIDが発行されますので、こちらもメモしておいてください。

f:id:kun432:20210627230634p:plain

API GatewayにCognitoユーザープールで認証をかける

ではAPI Gatewayに戻りましょう。左のメニューから「オーサライザー」をクリックします。

f:id:kun432:20210627233319p:plain

「新しいオーサライザーの作成」をクリックします。

f:id:kun432:20210627232207p:plain

名前は適当につけてください。今回はuser-pool-authにしました。タイプは「Cognito」を選択し、Cognitoユーザープールで先ほど作成したユーザープール名を選択します。「トークンのソース」はAuthorizationを入力します。最後に「作成」をクリックします。

f:id:kun432:20210628005306p:plain

オーサライザーが作成されました。ではAPIリクエスト時にこのオーサライザーを使うように設定します。「リソース」をクリックします。

f:id:kun432:20210627233419p:plain

/petsGETをクリックして、「メソッドリクエスト」をクリックします。

f:id:kun432:20210627233716p:plain

設定の「認可」のところにある鉛筆アイコンをクリックします。

f:id:kun432:20210627233915p:plain

先ほど作成したオーサライザー名が表示されますので、これを選択します。

f:id:kun432:20210627234044p:plain

選択したら、小さいチェックマークが表示されるのでクリックします。これで確定です。

f:id:kun432:20210627234215p:plain

これで認証の設定ができましたので、デプロイしましょう。「アクション」から「APIのデプロイ」をクリックします。

f:id:kun432:20210627234311p:plain

ステージを適当に設定します。今回はauthにしました。「デプロイ」をクリックします。

f:id:kun432:20210627234438p:plain

新しいステージでAPIのエンドポイントURLが発行されます。

f:id:kun432:20210627234618p:plain

curlでアクセスしてみましょう。/petsにアクセスしてみます。

$ curl https://XXXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/auth/pets
{"message":"Unauthorized"}

Unauthorizedと表示されてアクセスできませんでした。つまりCognitoの認証が必要になるということですね。認証を行って発行したトークンをAuthorizationヘッダで指定すればアクセス可能になります。

ちなみに/pets/{petid}の方は設定していないのでアクセスできます。エンドポイントごとに設定しないといけないのですね。

$ curl https://XXXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/auth/pets/1
{
  "id": 1,
  "type": "dog",
  "price": 249.99
}

Cognitoユーザープールへのユーザ追加

ではCognitoにユーザを作成しましょう。Cognitoの管理画面から追加すればいいのではないかなと思ったのですが、ちょっとうまく行かなかったのでaws-cliでやります。

まず、ユーザのサインアップ。メールアドレス等、適宜置き換えて実行してください。少し補足。

  • 指定したメールアドレスにメールアドレス検証用のメールが飛びますので、存在するメールアドレスを使用してください。
  • パスワードはデフォルトでルールが設定されています。アルファベット大文字・小文字、数字、記号の組み合わせで8文字以上みたいですね。
$ aws cognito-idp sign-up \
  --client-id アプリクライアントID \
  --username メールアドレス \
  --password パスワード \
  --user-attribute "Name=email,Value=メールアドレス"
{
    "UserConfirmed": false,
    "CodeDeliveryDetails": {
        "Destination": "****@****.***",
        "DeliveryMedium": "EMAIL",
        "AttributeName": "email"
    },
    "UserSub": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}

これでユーザが作成されます。Cognitoのユーザープールにも表示されていますね。

f:id:kun432:20210628001625p:plain

ただし、上記にもある通り、アカウントはUNCONFIRMED(未検証)となっていますので、検証を行う必要があります。上記メールアドレスのメールボックスを確認すると以下のようなメールが届いているかと思います。

f:id:kun432:20210628001747p:plain

この検証コードを使用して、ユーザアカウントの検証を行います。

$ aws cognito-idp confirm-sign-up \
  --client-id アプリクライアントID \
  --username メールアドレス \
  --confirmation-code 検証コード

ユーザープール上でもCONFIRMEDになれば、認証に利用できるようになります。

f:id:kun432:20210628001954p:plain

認証

ではCognitoで認証してサインインしてみます

$ aws cognito-idp admin-initiate-auth \
  --user-pool-id ユーザープールID \
  --client-id アプリクライアントID \
  --auth-flow ADMIN_USER_PASSWORD_AUTH \
  --auth-parameters "USERNAME=メールアドレス,PASSWORD=パスワード"
{
    "ChallengeParameters": {},
    "AuthenticationResult": {
        "AccessToken": "XXX...XXX",
        "ExpiresIn": 3600,
        "TokenType": "Bearer",
        "RefreshToken": "XXX...XXX",
        "IdToken": "XXX...XXX"
    }
}

サインインが成功すると、トークンが3つ返ってきます。API Gatewayの認証に必要なのはIdTokenですので、これを環境変数にセットします。

$ ID_TOKEN=$(aws cognito-idp admin-initiate-auth --user-pool-id ユーザープールID --client-id アプリクライアントID --auth-flow ADMIN_USER_PASSWORD_AUTH --auth-parameters "USERNAME=メールアドレス,PASSWORD=パスワード" | jq -r .AuthenticationResult.IdToken)

このIDトークンをAurhorizationヘッダに指定して、再度curlでAPIにアクセスしてみましょう。

$ curl https://XXXXXXXX.execute-api.ap-northeast-1.amaonaws.com/auth/pets
{"message":"Unauthorized"}

$ curl -H "Authorization:$ID_TOKEN" https://XXXXXXXX.execute-api.ap-northeast-1.amaonaws.com/auth/pets
[
  {
    "id": 1,
    "type": "dog",
    "price": 249.99
  },
  {
    "id": 2,
    "type": "cat",
    "price": 124.99
  },
  {
    "id": 3,
    "type": "fish",
    "price": 0.99
  }
]

はい、アクセスできましたね!

まとめ

とりあえずユーザープールはこんな感じ。IDプールも試してみたいのだけど、どうするのがよいかなぁ・・・