内容
メールアドレス+パスワード認証、Facebook認証によりサインインし、AWSサービスの一時的なアクセス権限を取得する。
それを使って、DynamoDBにアクセスしてデータを取得する。
ただし、DynamoDBには自分のIDに該当するデータしか取得することはできないように制限する。
以上を実現しました。
用語
CognitoIDプール(フェデレーティッドアイデンティティ)
ユーザに対してユニークなIDを生成する。
このIDにより、権限が制限された一時的なAWS認証情報を取得して、別のAWSサービスにアクセスすることができる
CognitoUserプール
ユーザのサインイン、サインアップなどの機能を提供する。
多要素認証や二段階認証、プロフィール管理など便利な機能が多い。
IDプール外部IDプロバイダー(今回はFacebook)
CognitoIDプールから得るユニークなIDをFacebookなどのソーシャルアカウント認証に基づいて取得するもの
サンプルアプリのリポジトリ
実装したコードは以下に置いてあります。
Info.plistにあるFacebookAppID/FacebookDisplayNameとConstant.swiftにある定数は自分の環境のものに書き換えてください。
ロジックフロー
具体的な実装に関してはリポジトリを参照してください。
(1) LoggedInViewControllerが生成される
storyBoardからrootViewControllerに指定してあるLoggedInViewControllerがまずはインスタンス化されて画面に表示されます
(2) LoggedInViewControllerのviewDidLoadで「CognitoClient.sharedInstance.credentialProvider.getIdentityId()」がcallされる
refreshメソッドの中の「CognitoClient.sharedInstance.fetchId()」は内部で.credentialProvider.getIdentityIdをcallしています。
(3)MyIdProbiderの「logins」がcallされる
.credentialProvider.getIdentityIdがcallされると、内部でAWSIdentityProviderManagerの.loginsがcallされます。
ここではじめて、どのアカウントでもサインインしていない事が発覚します。(サインインしている場合はIDが返されます)
(4)ログイン画面が表示される
どのアカウントでもサインインしていない場合、loginsの下の方にある「.userpool.currentUser()?.getDetails()」がcallされます。
これにより、サインインしていない場合は「AWSCognitoIdentityInteractiveAuthenticationDelegateのstartPasswordAuthentication()」がcallされます。
AWSCognitoIdentityInteractiveAuthenticationDelegateは今回AppDelegate内で準拠しています。
デリゲートの設定はCognitoClient.swiftから行なっていますので参照してみてください。
(5)ログインに成功するとdismissし、LoggedInViewControllerにIDが表示される
ログインに成功すると、AWSCognitoIdentityPasswordAuthenticationのdidCompleteStepWithErrorがcallされます。
この中でdismissとrefreshをしています。
ざっくりとした流れはこんな感じです。
LoggedInViewControllerのfetchボタンをタップすると、データが存在する場合は値を取得できるかと思います。
DynamoDBの行レベルアクセス制限を実現するためのIAMの設定
IAM Management Consoleへ行き、新規でポリシーを作ります。名前は何でも構いません。
JSONタブを選択し、ドキュメントに書かれているように以下のJSONを記載し、作成します。
(
ACCOUNTNUMBERはアカウント設定に書かれているアカウントIDの事です。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:UpdateItem" ], "Resource": [ "arn:aws:dynamodb:<REGION>:<ACCOUNTNUMBER>:table/<TABLE-NAME>" ], "Condition": { "ForAllValues:StringEquals": { "dynamodb:LeadingKeys": [ "${cognito-identity.amazonaws.com:sub}" ] } } } ] }
このポリシーをアタッチしていきます。
CognitoIDプールを作成したときに、「Cognito_****Auth_Role」といったロールが作成されていると思います。(デフォルト)
そこに先ほど作ったポリシーをアタッチします。
次に、DynamoDBにテーブルを作成します。この時テーブルの名前を先ほどポリシーを作る時に<TABLE-NAME>で指定した名前にすることを忘れないでください。
そして、パーティションキーにCognitoIDプールから得られるユーザのIDを入れます。これでユーザは自分のIDの行しか読み込むことができなくなります。
(サンプルアプリをそのまま動かすには、パーティションキーの名前を「userid」にして、その他のカラムは全てstring型にしておいてください)