話題の記事

[AWS][iOS] Amazon Cognito のモバイルユーザー認証 & データ同期 を iOS で使ってみた

2014.07.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Amazon Cognito でモバイルユーザー認証!

AWS Summit 2014 にて、Amazon Cognito *1というモバイル向けの新しいサービスが発表されました。Amazon Cognito はモバイル端末向けのサービスで利用できる、ユーザー認証や簡易的なデータストア(&同期)などを提供してくれるサービスです。このサービスを使うと、ユーザーが既に持っているであろう Amazon や Google、Facebook のアカウントを利用したログイン、そしてユーザーデータストアへの書き込みまでもさくっと作ることができます。ということで早速使ってみました!

概要はこちらにまとまっているので、あわせてご覧いただければと思います。

Amazon Cognito を使うために必要なもの

  • AWS アカウント
  • Xcode
  • AWS Mobile SDK for iOS
  • 各 ID プロバイダ (Facebook, Google, Amazon) のアプリ ID やトークン

使ってみよう

それでは早速使ってみましょう。以下のガイドを参考にやっていきます。

How to Authenticate Users | AWS Documentation

ID プロバイダのアプリ登録 (Facebook)

まず必要になるのが ID プロバイダ (Facebook とか) のアプリ ID です。他のサービスを使ってログインしちゃおうということなので、当然必要ですよね。ということで Facebook Developer のページにて作成します。Facebook 開発者アカウントが必要 *2です。

https://developers.facebook.com/

まず Facebook アプリを適当に作りましょう。アプリ名を入れて作成します。

facebook01

アプリが作成できるとアプリ ID が発行されるので、メモっておきます。次に「Add Platform」をクリックします。

facebook02

今回は iOS アプリで使いたいので 「iOS」を選択します。

facebook03

下図のような設定項目が表示されるようになるので、これから作成する iOS アプリに設定するであろう Bundle ID を入れておきます。また、リリース後は App Store ID なども入力するようにします。

facebook04

これで Facebook アプリの設定は終わりです。

Cognito identity pool の作成

次に Cognito identity pool というのを作成します。まずは Cognito のコンソールを開きましょう。現在は Versinia リージョンでしか作成できないので注意してください。

https://console.aws.amazon.com/cognito/

cognito01

では早速作成しましょう。

cognito02

ステップ1では次の項目の入力が必要です。

項目 説明
Identity Pool Name アプリ名
Amazon Client ID Amazon のアプリ ID (任意)
Facebook App ID Facebook のアプリ ID (任意)
Google Project ID Google のプロジェクト ID (任意)
Enable Access to Unauthenticated Identities 匿名ユーザーアクセスの許可

次に進むと、IAM の設定が表示されます。IAM とは (簡単に説明すると) AWS サービスのうち、どのサービスのどの機能を使うことをできるようにするか適切に設定するための機能です。この画面から作成することもできますし、作成済みの IAM を選択することもできます。

cognito03

Assign Role Authenticated Identities は ID プロバイダを利用したログインを行う場合に使う IAM Role、Assign Role Unauthenticated Identities は匿名ユーザーとしてサービスを使いたい場合に使う IAM Role です。

ここまで入力できれば終わりです。サンプルコードが表示されます。また、サンプルアプリもダウンロードできるのでこちらを試してみても良いかと思います。

cognito04

Cognito を使った iOS アプリを作ってみる

いよいよ iOS アプリに組み込むところです。

AWS Mobile SDK for iOS を CocoaPods でインストールします。バージョン2は AWSiOSSDKv2 という名前で、これまでのとは違うので注意してください。また、Cognito のデータストレージ機能を使うには AWSCognitoSync も必要です。

pod "AWSiOSSDKv2"
pod "AWSCognitoSync"
pod "Facebook-iOS-SDK"

匿名アカウントで使ってみる

まずは Cognito のメイン機能である ID プロバイダ連係のログインです。今回は ViewController で起動回数の保存みたいな処理を実装してみました。ほとんどサンプルコードのまんまですw

#import "COGViewController.h"
#import "AWSCore.h"
#import <AWSCognitoSync/Cognito.h>

@interface COGViewController ()

@end

@implementation COGViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // プロバイダの作成
    AWSCognitoCredentialsProvider *credentialsProvider = [AWSCognitoCredentialsProvider
                                                          credentialsWithRegionType:AWSRegionUSEast1
                                                          accountId:@"ACCOUNT_ID"
                                                          identityPoolId:@"IDENTITY_POOL_ID"
                                                          unauthRoleArn:@"UNAUTH_ROLE_ARN"
                                                          authRoleArn:@"AUTH_ROLE_ARN"];
    
    // 設定
    AWSServiceConfiguration *configuration = [AWSServiceConfiguration configurationWithRegion:AWSRegionUSEast1
                                                                          credentialsProvider:credentialsProvider];
    
    [AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
    
    // 匿名ログイン
    [[credentialsProvider getIdentityId] continueWithSuccessBlock:^id(BFTask *task){
        NSString* cognitoId = credentialsProvider.identityId;
        NSLog(@"cognitoId: %@", cognitoId);
        [self launchCount];
        return nil;
    }];
    
}

- (void)launchCount
{
    AWSCognito *syncClient = [AWSCognito defaultCognito];
    AWSCognitoDataset *dataset = [syncClient openOrCreateDataset:@"myDataSet"];
    
    // 取得
    int value = [[dataset stringForKey:@"launchCount"] intValue];
    NSLog(@"launchCount : %d", value);
    
    // 削除(ローカルのみ)
    [dataset clear];
    
    // 保存
    [dataset setString:[NSString stringWithFormat:@"%d", value + 1] forKey:@"launchCount"];
    
    // 同期
    [[dataset synchronize] continueWithBlock:^id(BFTask *task) {
        if (task.isCancelled) {
            NSLog(@"同期キャンセル");
        } else if (task.error) {
            NSLog(@"同期エラー: %@",task.error);
        } else {
            NSLog(@"同期成功");
        }
        return nil;
    }];
}

@end

って、よく見てみると非同期処理に Bolts が使われていますね!新しい AWS Mobile SDK for iOS の非同期処理は Bolts のフレームワークを使って実装されているようです。 個人的には非同期処理にもっぱら Bolts を使っていたので、かなりありがたいです!

それでは実行してみましょう。画面はなにもいじっていないので、ログでの確認になりますが、無事に同期が成功しました!

cognito05

ちなみに openOrCreateDataset で設定している datasetName は一意なので、他のユーザーが実行すると conflictHandler が呼び出されます。

Facebook アカウントでログインしてみる

次に Facebook アカウントでログインしてみましょう!まずは Facebook の通常のログイン処理の実装を行います。アプリの Info.plist を開き、FacebookAppIDURL types を追加します。URL types は中に URL Schemes を入れて、その中のアイテムに頭文字に fb を付けたアプリ ID を入れます。

parse_fb04

次に AppDelegate を開き、次のように実装します。

#import "COGAppDelegate.h"
#import <FacebookSDK/FacebookSDK.h>

@implementation COGAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    return YES;
}
							
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation
{
    
    [[FBSession activeSession] handleOpenURL:url];
    
    BOOL wasHandled = [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
    return wasHandled;
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    [[FBSession activeSession] close];
}

@end

最後に、先ほど実装した ViewController を、以下のように書き換えます。

#import "COGViewController.h"
#import "AWSCore.h"
#import <AWSCognitoSync/Cognito.h>
#import <FacebookSDK/FacebookSDK.h>

@interface COGViewController ()

@end

@implementation COGViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [FBSession openActiveSessionWithReadPermissions:@[@"email"]
                                       allowLoginUI:true
                                  completionHandler:^(FBSession *session,
                                                      FBSessionState status,
                                                      NSError *error)
    {
        if (status == FBSessionStateClosedLoginFailed || status == FBSessionStateCreatedOpening) {
            
            NSLog(@"Facebookログイン失敗");
            [[FBSession activeSession] closeAndClearTokenInformation];
            [FBSession setActiveSession:nil];
            
        } else {
            
            NSLog(@"Facebookログイン成功");
            
            [FBSession setActiveSession:session];
            
            AWSCognitoCredentialsProvider *credentialsProvider = [AWSCognitoCredentialsProvider
                                                                  credentialsWithRegionType:AWSRegionUSEast1
                                                                  accountId:@"ACCOUNT_ID"
                                                                  identityPoolId:@"IDENTITY_POOL_ID"
                                                                  unauthRoleArn:@"UNAUTH_ROLE_ARN"
                                                                  authRoleArn:@"AUTH_ROLE_ARN"];

            NSString *token = FBSession.activeSession.accessTokenData.accessToken;
            credentialsProvider.logins = @{ @(AWSCognitoLoginProviderKeyFacebook): token };
            
            AWSServiceConfiguration *configuration = [AWSServiceConfiguration configurationWithRegion:AWSRegionUSEast1
                                                                                  credentialsProvider:credentialsProvider];
            
            [AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
            
            [[credentialsProvider getIdentityId] continueWithSuccessBlock:^id(BFTask *task){
                NSString* cognitoId = credentialsProvider.identityId;
                NSLog(@"cognitoId: %@", cognitoId);
                [self launchCount];
                return nil;
            }];
            
        }
    }];
}

- (void)launchCount
{
    AWSCognito *syncClient = [AWSCognito defaultCognito];
    AWSCognitoDataset *dataset = [syncClient openOrCreateDataset:@"myDataSet"];
    
    // 取得
    int value = [[dataset stringForKey:@"launchCount"] intValue];
    NSLog(@"launchCount : %d", value);
    
    // 削除(ローカルのみ)
    [dataset clear];
    
    // 保存
    [dataset setString:[NSString stringWithFormat:@"%d", value + 1] forKey:@"launchCount"];
    
    // 同期
    [[dataset synchronize] continueWithBlock:^id(BFTask *task) {
        if (task.isCancelled) {
            NSLog(@"同期キャンセル");
        } else if (task.error) {
            NSLog(@"同期エラー: %@",task.error);
        } else {
            NSLog(@"同期成功");
        }
        return nil;
    }];
}

@end

これで実行すると、Facebook アプリの認証画面(インストールされていない場合はダイアログ)が表示されます。

cognito06

認証してログインすると、先ほどと同様にデータ同期ができます。また Cognito コンソールを見てみると、Facebook ログインが無事に成功したことが分かります。

cognito07

まとめ

Cognito の登場によって、AWS をより mBaaS っぽく使えるようになりました!また、IAM Role をカスタマイズして、Dynamo DB など他の AWS サービスにアクセスすることも可能なので、うまく使いこなせれば AWS を直接 mBaaS として使えるかも知れません。今後も追っていきたいと思います!

脚注

  1. cognito(こぐにーと) は incognito(イタリア語) の反意語で「身分が明らかになっている」などの意味になります。
  2. Facebook アプリの作成するアカウントは、最近 Facebook ユーザーでないと作成できなくなりました。