AndroidでGoogleアカウントを使ってCognito認証 #アドカレ2015
丹内です。
皆さんおなじみAmazon Cognitoのウェブアイデンティティフェデレーションに使うことのできるIdentity Providerに、Googleが含まれていることをご存知でしょうか。
FacebookやAmazon、Twitterでの認証事例に比べて、Googleアカウントを使った認証はあまり見ない印象です。
ということで、やってみます。
Cognito Identity Poolを作成する
こちらの記事を参考にして、Identity Poolを作成します。
Unauthenticated Identities
は有効にしなくても大丈夫です。
IAMからIdentity Providerを設定する
Cognitoのドキュメントを見ると、
NOTE: If your app uses Google and will be available on multiple mobile platforms, you should configure it as a OpenID Connect Provider, adding all created client IDs as additional audience values to allow for better integration. To learn more about Google's cross-client identity model, see Cross-client Identity.
と注意書きがあります。
実はGoogleの認証にはサイレントログインという機能があり、FacebookやTwitterのようにCognitoを使うと、外部IdPでは同じIdentityであっても、Cognito上では異なるIdentityとなっていしまうようです。これは意図する挙動ではありません。
そのため、Google認証をIAMでIdentity Providerとして設定し、Cognitoはそれを指定するという形をとります。
まず、Google Developer Consoleでプロジェクトを作成し、「認証情報」の画面から新しい認証情報を作成します。
このときに作成するのはOAuth2.0クライアントIDで、ウェブアプリケーションを選択してください。
生成されたクライアントIDは、以下のようなフォーマットになっています。
<ProjectのID>-<ランダムな文字列>.apps.googleusercontent.com
また、後で必要なので、Android用のクライアントIDも作成してください。
- Provider Typeは「OpenID Connect」
- Provider URLは「https://accounts.google.com」
- Audienceは先ほど生成したWebアプリ用GooleクライアントID
以上を入力したら、保存します。
ここまでくると、Cognito Identity Poolの編集画面でGoogleを設定できるようになっているはずです。
チェックを入れたら、保存して、Cognitoは一旦完了です。
アプリに認証を実装する
それでは、アプリに認証を実装していきましょう。
Cognitoの処理についてのみのサンプルです。
適宜置き換えてください。
private void handleSignInResult(GoogleSignInResult result) { if (result.isSuccess()) { GoogleSignInAccount account = result.getSignInAccount(); Log.d(TAG, "IdToken: " + account.getIdToken()); googleAuthenticationStream(account) .flatMap(this::cognitoAuthenticationStream) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( response -> Toast.makeText(getActivity(), provider.getCachedIdentityId(), Toast.LENGTH_SHORT).show(), Throwable::printStackTrace, () -> Log.d(TAG, "onCompleted") ); } } Observable<String> googleAuthenticationStream(final GoogleSignInAccount account) { return Observable.create(subscriber -> { String token = ""; try { token = GoogleAuthUtil.getToken(getContext(), account.getEmail(), "audience:server:client_id::Webアプリ用Google Oauth2.0 クライアントID"); } catch (UserRecoverableAuthException e) { e.printStackTrace(); } catch (GoogleAuthException | IOException e) { e.printStackTrace(); } subscriber.onNext(token); }); } Observable<CognitoCachingCredentialsProvider> cognitoAuthenticationStream(final String googleOAuthToken) { return Observable.create(subscriber -> { CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider( getActivity().getApplicationContext(), "122345", // AWSアカウントID "ap-northeast-1:123-356", // Identity Pool ID "arn:aws:iam::122345:role/Cognito_testUnauth_Role", "arn:aws:iam::122345:role/Cognito_testAuth_Role", Regions.AP_NORTHEAST_1 // Region ); Map<String, String> logins = new HashMap<>(); logins.put("accounts.google.com", googleOAuthToken); credentialsProvider.setLogins(logins); subscriber.onNext(credentialsProvider); }); }
まとめ
Google認証はちょっとむずかしいですが、このようにして実装できます。