2014年8月24日

Cognito を Web サイトで使う

AWS Mobile Development のブログに Cognito を website で使う方法が紹介されていました。
Use Amazon Cognito in your website for simple AWS authentication

いつのまにか Cognito はモバイルだけでなく、他の SDK でも使えるようになっていました。
Cognito のドキュメントには Identity API Reference と Sync API Reference が用意されていました。

Cognito
Identity API Reference
Sync API Reference

Identity API


Identity API は Cognito の認証系を扱う API となります。

たとえばこんなコードでその IdentityPool に保持されている IdentityId を取得できたりします。
public static void main(String[] args) {
  AWSCredentials credentials = new BasicAWSCredentials(
      ACCESS_KEY,
      SECRET_KEY
  );
 
  AmazonCognitoIdentity identityClient = new AmazonCognitoIdentityClient(credentials);

  ListIdentitiesRequest listIdentitiesRequest = new ListIdentitiesRequest()
    .withIdentityPoolId(IDENTITY_POOL_ID).withMaxResults(60);
  ListIdentitiesResult result =  identityClient.listIdentities(listIdentitiesRequest);

  for (IdentityDescription identityDescription : result.getIdentities()) {
   String identityId = identityDescription.getIdentityId();
   System.out.println(identityId);
  }
 }

この IdentityId は GetId API で取得できます。

サンプルはブログにあるとおりです。
// anonymous AWS credentials で初期化します
 AmazonCognitoIdentity identityClient = new AmazonCognitoIdentityClient(
   new AnonymousAWSCredentials());

 // ID の発行をします。この ID はユーザで一意の ID になります
 GetIdRequest idRequest = new GetIdRequest();
 idRequest.setAccountId(AWS_ACCOUNT_ID);
 idRequest.setIdentityPoolId(IDENTITY_POOL_ID);

 // Facebook のセッションキーを設定(設定が無い場合には Unauthenticated になります)
 if (facebookSessionKey != null) {
  Map providerTokens = new HashMap();
  providerTokens.put("graph.facebook.com", facebookSessionKey);
  idRequest.setLogins(providerTokens);
 }

 GetIdResult idResp = identityClient.getId(idRequest);

 String identityId = idResp.getIdentityId();

AnonymousAWSCredentials はソースを見るとシークレットキー・アクセスキーが null となってます。
署名無しで API が使えるのですね。

STS を使用して identityId から OpenIdToken を取得して Cognito に渡す Creential を作成します。
このコードだと Authenticated も Unauthenticated も同じ Role になってしまいますが、実際は mobile のときのように Role 使い分けないといけないです。
// OpenIdToken を取得
 GetOpenIdTokenRequest tokenRequest = new GetOpenIdTokenRequest();
 tokenRequest.setIdentityId(identityId);

 if (facebookSessionKey != null) {
  Map providerTokens = new HashMap();
  providerTokens.put("graph.facebook.com", facebookSessionKey);
  tokenRequest.setLogins(providerTokens);
 }
 GetOpenIdTokenResult tokenResp = identityClient.getOpenIdToken(tokenRequest);

 String openIdToken = tokenResp.getToken();

 // STS を使って role を取得
 AWSSecurityTokenService stsClient = new AWSSecurityTokenServiceClient(
   new AnonymousAWSCredentials());
 AssumeRoleWithWebIdentityRequest stsReq = new AssumeRoleWithWebIdentityRequest();
 stsReq.setRoleArn(AWS_ROLE_ARN);
 stsReq.setWebIdentityToken(openIdToken);
 stsReq.setRoleSessionName("AppTestSession");

 AssumeRoleWithWebIdentityResult stsResp = stsClient.assumeRoleWithWebIdentity(stsReq);
 Credentials stsCredentials = stsResp.getCredentials();

 // 一時 Credential を作成
 AWSSessionCredentials sessionCredentials = new BasicSessionCredentials(
   stsCredentials.getAccessKeyId(),
   stsCredentials.getSecretAccessKey(),
   stsCredentials.getSessionToken());

Sync API


Sync API を使えば Dataset の取得や更新ができるようです。

Credential は前述のコードで作成しています。

前述のブログを参考に作成したところ、Unauthenticated identityId では参照・更新ができました。
Facebook で認証した identityIdに対して認証無しで実行した場合には例外が発生してしまいました。(当たり前といえば当たり前ですが)

// syncClient に AWSSessionCredentials を設定
 AmazonCognitoSync syncClient = new AmazonCognitoSyncClient(sessionCredentials);

 if (identityDescription.getLogins() != null) {
  for (String login : identityDescription.getLogins()) {
   System.out.println(login);
  }
 }

 // データセットを取得
 ListDatasetsRequest listDatasetsRequest = new ListDatasetsRequest()
  .withIdentityPoolId(IDENTITY_POOL_ID).withIdentityId(identityId);
 ListDatasetsResult datasetsResult = syncClient.listDatasets(listDatasetsRequest);
 System.out.println(datasetsResult);

 // レコードを取得
 ListRecordsRequest listRecordsRequest = new ListRecordsRequest()
   .withIdentityPoolId(IDENTITY_POOL_ID)
   .withIdentityId(identityId)
   .withDatasetName("test");
 ListRecordsResult listRecordsResult = syncClient.listRecords(listRecordsRequest);
 System.out.println(listRecordsResult);

 String token = listRecordsResult.getSyncSessionToken();
 
 // レコードの更新
 UpdateRecordsRequest updateRecordsRequest = new UpdateRecordsRequest()
   .withDatasetName("test")
   .withIdentityId(identityId)
   .withIdentityPoolId(IDENTITY_POOL_ID)
   .withSyncSessionToken(token)
   .withRecordPatches(
     new RecordPatch()
       .withKey("test")
       .withValue("value")
       .withOp(Operation.Replace)
       .withSyncCount(listRecordsResult.getDatasetSyncCount()));
 syncClient.updateRecords(updateRecordsRequest);

これでモバイルアプリと Web アプリの連携ができますね!

0 コメント:

コメントを投稿