[AWS][iOS] Amazon Cognito のモバイルユーザー認証 & データ同期 を iOS で使ってみた
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 アプリを適当に作りましょう。アプリ名を入れて作成します。
アプリが作成できるとアプリ ID が発行されるので、メモっておきます。次に「Add Platform」をクリックします。
今回は iOS アプリで使いたいので 「iOS」を選択します。
下図のような設定項目が表示されるようになるので、これから作成する iOS アプリに設定するであろう Bundle ID を入れておきます。また、リリース後は App Store ID なども入力するようにします。
これで Facebook アプリの設定は終わりです。
Cognito identity pool の作成
次に Cognito identity pool というのを作成します。まずは Cognito のコンソールを開きましょう。現在は Versinia リージョンでしか作成できないので注意してください。
https://console.aws.amazon.com/cognito/
では早速作成しましょう。
ステップ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 を選択することもできます。
Assign Role Authenticated Identities は ID プロバイダを利用したログインを行う場合に使う IAM Role、Assign Role Unauthenticated Identities は匿名ユーザーとしてサービスを使いたい場合に使う IAM Role です。
ここまで入力できれば終わりです。サンプルコードが表示されます。また、サンプルアプリもダウンロードできるのでこちらを試してみても良いかと思います。
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 が使われていますね! 個人的には非同期処理にもっぱら Bolts を使っていたので、連係しやすいのでかなりありがたいです。
それでは実行してみましょう。画面はなにもいじっていないので、ログでの確認になりますが、無事に同期が成功しました!
ちなみに openOrCreateDataset で設定している datasetName は一意なので、他のユーザーが実行すると conflictHandler が呼び出されます。
Facebook アカウントでログインしてみる
次に Facebook アカウントでログインしてみましょう!まずは Facebook の通常のログイン処理の実装を行います。アプリの Info.plist を開き、FacebookAppID と URL types を追加します。URL types は中に URL Schemes を入れて、その中のアイテムに頭文字に fb を付けたアプリ ID を入れます。
次に 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 アプリの認証画面(インストールされていない場合はダイアログ)が表示されます。
認証してログインすると、先ほどと同様にデータ同期ができます。また Cognito コンソールを見てみると、Facebook ログインが無事に成功したことが分かります。
まとめ
Cognito の登場によって、AWS をより mBaaS っぽく使えるようになりました!また、IAM Role をカスタマイズして、Dynamo DB など他の AWS サービスにアクセスすることも可能なので、うまく使いこなせれば AWS を直接 mBaaS として使えるかも知れません。今後も追っていきたいと思います!