この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
丹内です。
皆さんおなじみ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認証はちょっとむずかしいですが、このようにして実装できます。