話題の記事

[新機能] Amazon Cognito に待望のユーザー認証基盤「User Pools」が追加されました!

2016.04.21

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

Cognito のユーザー認証基盤!

AWS Summit 2016 Chicago にて Amazon Cognito の新機能「User Pools」が発表されました!! 本日 (2016/04/21) より Public Beta がご利用いただけます。

これまで Cognito の認証には Amazon や Google、Facebook、Twitter またはカスタムプロバイダ (自前) のアカウントが使用できましたが、 User Pools では Cognito がユーザーアカウントの基盤を持ち、アカウント登録やサインアップなどといった機能をマネージドに提供してくれます。 AWS らしいスケール可能で安全なユーザー認証基盤を簡単に構築することができます。

User Pool の作成

User Pool の作成は Cognito の Management Console から行えます。または AWS CLI の create-user-pool を実行する方法なども既に提供されています。

ということで早速作ってみましょう。まずは Manage your user identities を選び Create new pool を選びます。

cognito01

cognito02

ここからは、これから作成する User Pool の設定を行います。まずは名前。

cognito03

次は Attributes です。これは、ユーザー情報としてどのような属性値を付けるか決める設定です。 Required に付けるとアカウント登録時に設定が必須になります。ここに表示されている他に Custom Attribute も作成可能です。

cognito04

次は Policies です。ここでは、ユーザーのパスワードのルールを決めます。最小何文字か、最大何文字か、数字や英字の組み合わせが必須か、などといった細かいポリシーを設定できます。

cognito05

次は Verifications です。ここでは、アカウント登録しているユーザーへの MFA (他要素認証) に関する設定が行えます。必須ではありませんが、採用した方がセキュアにサインインさせることができます。 MFA には 電話番号またはメールによる認証が行えます。

cognito06

次は Apps です。ここでは、作成する User Pool にアクセスできるクライアントを複数設定できます。

cognito07

次は Triggers です。ここでは、サインアップやサインインなどが行われたときに呼び出す、任意の Lambda Function を設定できます。

cognito08

次のようなイベントをフックできます。

ライフサイクル 説明
Pre sign-up サインアップのリクエストが送られたときに呼ばれる。独自のバリデートを挟むことも可能。
Custom message 認証または MFA のメッセージを送信する前に呼ばれる。メッセージを動的に作成可能。
Pre authentication サインインのリクエストが送られたときに呼ばれる。IP 縛りなどのようなバリデートを挟むことが可能。
Post authentication サインインが完了したときに呼ばれる。ログやアナリティクスへの送信などの処理を挟むことが可能。
Post confirmation ユーザーの登録が完了したときに呼ばれる。ログやアナリティクスへの送信などの処理を挟むことが可能。

以上で User Pool の作成が終わりました! Pool Id が発行されています。

cognito10

Apps を見てみると、ClientID と ClientSecret が発行されています。

cognito11

iOS アプリから使う

上記で作成した User Pool を利用して iOS アプリでサインアップやサインインを行ってみましょう。

Xcode プロジェクトを適当に作成しまして、CocoaPods 経由で AWS SDK for iOS をインポートします。

Podfile

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'

target 'YOUR_APP_NAME' do

  pod 'AWSCore'
  pod 'AWSCognitoIdentityProvider'

end

pod install でインポートは終わりです。

AWSCognitoIdentityUserPool オブジェクトの生成

iOS アプリで User Pool にアクセスするには AWSCognitoIdentityUserPool オブジェクト経由で行います。AWSCognitoIdentityUserPool の登録は、次のコードのように行います。AppDelegate クラスに書いておくと良いでしょう。

#import <AWSCognitoIdentityProvider/AWSCognitoIdentityProvider.h>
#import "AppDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // AWSServiceConfiguration には CredentialsProvider は渡さない
    AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:nil];
    [AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
    
    // Register しておく
    AWSCognitoIdentityUserPoolConfiguration *userPoolConfiguration = [[AWSCognitoIdentityUserPoolConfiguration alloc] initWithClientId:@"CLIENT_ID"
                                                                                                                          clientSecret:@"CLIENT_SECRET"
                                                                                                                                poolId:@"USER_POOL_ID"];
    [AWSCognitoIdentityUserPool registerCognitoIdentityUserPoolWithUserPoolConfiguration:userPoolConfiguration
                                                                                  forKey:@"AmazonCognitoIdentityProvider"];
    return YES;
}
                                                                                  
@end

registerCognitoIdentityUserPoolWithUserPoolConfiguration: メソッドで登録しておくことで、キーである AmazonCognitoIdentityProvider を渡せばどこでも AWSCognitoIdentityUserPool オブジェクトにアクセスできるようになります。例えば、下記は ViewController から取得した場合です。

#import "ViewController.h"

#import <AWSCognitoIdentityProvider/AWSCognitoIdentityProvider.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    AWSCognitoIdentityUserPool * pool = [AWSCognitoIdentityUserPool CognitoIdentityUserPoolForKey:@"AmazonCognitoIdentityProvider"];
    
    // ...任意の API を呼ぶことができる
}

@end

あとはこの AWSCognitoIdentityUserPool オブジェクトを使って、サインアップやサインインを行うことができます。ドキュメントに記載されている一通りの機能の実装方法を紹介します。

サインアップ

サインアップにはユーザー名とパスワード、そして認証に使うメールアドレスや電話番号を設定します。メールアドレスと電話番号が必要かどうかは User Pool を作成した時の設定値に依ります。

AWSCognitoIdentityUserAttributeType * phone = [AWSCognitoIdentityUserAttributeType new];
phone.name = @"phone_number";
phone.value = @"+15555555555";
AWSCognitoIdentityUserAttributeType * email = [AWSCognitoIdentityUserAttributeType new];
email.name = @"email";
email.value = @"email@mydomain.com";
    
//sign up the user
[[pool signUp:@"username" password:@"password" userAttributes:@[email,phone] validationData:nil] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUser *> * _Nonnull task) {
    if (task.error) {
    } else {
        AWSCognitoIdentityUser * user = task.result;
        //need to confirm user using user.confirmUser:
    }
    return nil;
}];

電話番号を使う場合は、上記処理を実行すると SMS が届きます。

IMG_5397

ここで受け取った認証コードを confirmSignUp: メソッドで渡すと認証が成功し、アカウントが有効になります!

AWSCognitoIdentityUser *user = [pool getUser:@"username"];
[[user confirmSignUp:@"xxxxxx"] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserConfirmSignUpResponse *> * _Nonnull task) {
    if (task.error) {
        NSLog(@"%@", task.error);
    } else {
        NSLog(@"%@", task.result);
    }
    return nil;
}];

Management Console で確認してみると Confirmed になっていることが確認できます。

cognito-user

ユーザーの取得

ユーザーを取得するには、幾つかの方法が用意されています。

//get the last logged in user
[pool currentUser];
    
//get a user without a username
[pool getUser];
  
//get a user with a specific username
[pool getUser:@"username"];

ユーザー属性の検証

[[user getAttributeVerificationCode:@"phone_number"] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserGetAttributeVerificationCodeResponse *> * _Nonnull task) {
    //success
    return nil;
}];
    
[[user verifyAttribute:@"phone_number"code:@"code"] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserVerifyAttributeResponse *> * _Nonnull task) {
    //success
    return nil;
}];

サインイン

[user getSession:@"username" password:@"password" validationData:nil scopes:nil];

パスワードリセット

[[user forgotPassword] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserForgotPasswordResponse*> * _Nonnull task) {
    //success
    return nil;
}];
    
[[user confirmForgotPassword:@"code" password:@"newPassword"] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserConfirmForgotPasswordResponse *> * _Nonnull task) {
    //success
    return nil;
}];

ユーザー属性の取得

[[user getDetails] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserGetDetailsResponse *> * _Nonnull task) {
    if (task.error) {
    } else {
        AWSCognitoIdentityUserGetDetailsResponse *response = task.result;
        //do something with response.userAttributes
    }
    return nil;
}];

ユーザー属性の更新

AWSCognitoIdentityUserAttributeType * attribute = [AWSCognitoIdentityUserAttributeType new];
attribute.name = @"name";
attribute.value = @"John User";
[[user updateAttributes:@[attribute]] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserUpdateAttributesResponse *> * _Nonnull task) {
    //success
    return nil;
}];

パスワードの変更

[[user changePassword:@"currentPassword" proposedPassword:@"proposedPassword"] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserChangePasswordResponse *> * _Nonnull task) {
        //success
        return nil;
}];

MFA の有効化

AWSCognitoIdentityUserSettings * settings = [AWSCognitoIdentityUserSettings new];
AWSCognitoIdentityUserMFAOption * mfaOptions = [AWSCognitoIdentityUserMFAOption new];
mfaOptions.attributeName = @"phone_number";
mfaOptions.deliveryMedium = AWSCognitoIdentityProviderDeliveryMediumTypeSms;
settings.mfaOptions = @[mfaOptions];
[[user setUserSettings:settings] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSetUserSettingsResponse *> * _Nonnull task) {
    //success
    return nil;
}];

まとめ

Cognito を使う上で一番の課題だったユーザー登録機能が、ついに AWS から提供されました。実用的な機能をより簡単に構築できるため、これを使わない手はないです。まずは触ってみてください!

まだ掘り下げきれていない内容もあるので、別な記事でご紹介したいと思います!

参考