1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Sign In with AppleでAWSサービスに接続する

Posted at

はじめに

こんにちは。Daddy's Officeの市川です。

先日、「LiveCapture3 Remote」のiOS版をリリースしました。
今回は開発にXamarin.Formsを使用して、Android/iOS両対応の開発を行いました。

「LiveCapture3 Remote」では、クラウドサーバにAWSを使用したアプリケーションですが、Android版のアプリサインインは、Googleアカウントでサインインし、AWS Cognitoでユーザに対して適切なIAM権限を付与する形で実現しています。

Googleアカウントでのサインインに関してはこちらを参照してください。
GoogleアカウントでAWSサービスに接続する

今回iOS版では、必須になっているSign In with Appleでサインインし、Android版と同様に、AWS Cognitoで適切なIAM権限をアプリに付与してAWSの各種サービスに直接アクセスできるようにしました。

今回は、このやり方を説明しようと思います。

ちなみに「LiveCapture3 Remote」はiOS13以降のみ対応なので、iOS12以前の説明は行いません。(というか分かりません。。。)

Sign In with Appleの有効化

まず、Apple Developerで、Sign In with Appleを有効にします。

Apple Developerを開き、(アプリのApp IDを登録していない場合は登録して)、「Certificates, Identifiers & Profiles」で対象アプリを選択します。

AppDeveloper01.jpg

設定の「Capabilities」をスクロールすると「Sign In with Apple」がありますので、チェックを付けます。

AppDeveloper02.jpg

あとは、プロジェクトのEntitlements.plistに「com.apple.developer.applesignin」のキーを下記のように追加します。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.developer.applesignin</key>
	<array>
		<string>Default</string>
	</array>
</dict>
</plist>

IDプロバイダーの追加(AWS)

Apple IDアカウントで認証済みのアプリからのアクセスに対して、AWSサービスへアクセスするAWS認証情報を発行するために、CognitoのIDプールとApple IDアカウントを連携させます。

IAMの「IDプロバイダー」を選択して、「プロバイダの作成」ボタンをクリックします。

IAM01.jpg

項目 入力値
プロバイダーのタイプ OpenID Connect
プロバイダーのURL https:///appleid.apple.com
対象者 App Developerで設定したアプリのIdentifier(com.xxxxx.xxxxx)

上記を入力して、IDプロバイダー(appleid.apple.com)を作成します。

Cognito IDプールの作成(AWS)

OpenIDのIDプロバイダを追加すると、CognitoのIDプール作成画面のOpenIDのタブに、今追加した「appleid.apple.com」が選択肢として表示されますので、チェックを入れます。

Cognito01.jpg

今回は認証されていないIDのアクセスは拒否しますので、そのままIDプールを作成します。

AWS認証情報の権限設定

CognitoでIDプールを作成すると、2つのIAMロールが生成されます。

  • Cognito_xxxxxxAuth_Role (認証済みユーザ用のIAMロール)
  • Cognito_xxxxxxUnauth_Role(認証されていないユーザ用のIAMロール)

(xxxxxxは作成したIDプールの名称です)

先ほどのIDプール作成で、「認証されていないIDに対してのアクセスを有効にする」にチェックを入れると、認証していないユーザにもAWSサービスへのアクセスを許可することができます。

ただ、今回は使用しませんので、認証済みユーザ向けの「Cognito_xxxxxxxAuth_Role」の方に、必要なアクセス権を設定します。

#実装

以下を参考に実装します。
Xamarin.iOS Appleでのサインイン

今回はXamarin.Formsを使用して開発していますので、Sign In with Appleの処理はDependency Serviceとして実装します。
(Android側はGoogle SignInの処理を記述しました)

iOS側のDependency Serviceは以下のような感じです。

[assembly: Xamarin.Forms.Dependency(typeof(AppleSignInService))]
namespace lc3remote.iOS.Services
{
    public class AppleSignInService: NSObject, ISignInService,IASAuthorizationControllerDelegate, IASAuthorizationControllerPresentationContextProviding
    {
        AuthManager authManager;

        public async Task<SignInUser> SignInAsync()
        {
            var appleIdProvider = new ASAuthorizationAppleIdProvider();
            var request = appleIdProvider.CreateRequest();
            request.RequestedScopes = new[] { ASAuthorizationScope.Email, ASAuthorizationScope.FullName };

            authManager = new AuthManager(UIApplication.SharedApplication.KeyWindow);

            var authorizationController = new ASAuthorizationController(new[] { request });
            authorizationController.Delegate = authManager;
            authorizationController.PresentationContextProvider = authManager;
            authorizationController.PerformRequests();

            var creds = await authManager.Credentials;

            if (creds == null)
                return null;

            var user = new SignInUser(); 	// 共通ユーザクラス
            user.Id = creds.User;			// ユーザID
            user.jwt = new NSString(creds.IdentityToken, NSStringEncoding.UTF8).ToString(); // JWT Token

            return user;

        }

        //
        // awaitできるようにSignIn処理をクラス化する
        //
        class AuthManager : NSObject, IASAuthorizationControllerDelegate, IASAuthorizationControllerPresentationContextProviding
        {
            public Task<ASAuthorizationAppleIdCredential> Credentials
                => tcsCredential?.Task;

            TaskCompletionSource<ASAuthorizationAppleIdCredential> tcsCredential;

            UIWindow presentingAnchor;

            public AuthManager(UIWindow presentingWindow)
            {
                tcsCredential = new TaskCompletionSource<ASAuthorizationAppleIdCredential>();
                presentingAnchor = presentingWindow;
            }

            public UIWindow GetPresentationAnchor(ASAuthorizationController controller)
                => presentingAnchor;

            [Export("authorizationController:didCompleteWithAuthorization:")]
            public void DidComplete(ASAuthorizationController controller, ASAuthorization authorization)
            {
                var creds = authorization.GetCredential<ASAuthorizationAppleIdCredential>();
                tcsCredential?.TrySetResult(creds);
            }

            [Export("authorizationController:didCompleteWithError:")]
            public void DidComplete(ASAuthorizationController controller, NSError error)
                => tcsCredential?.TrySetException(new Exception(error.LocalizedDescription));
        }
    }
}

Sign In with Appleの実装詳細に関しては別の文献を参照してください。
(名前とメールアドレスは最初の1回目しか取得できないとか、色々と癖があります。。。)

サインインが成功するとASAuthorizationAppleIdCredentialが取得できます。
このクラスのIdentityTokenメンバーがOpenIDで使用するJWTトークンになりますので、それを使用して、AWSサービスにアクセスする際のCredentialオブジェクトを生成します。

  var credentials = new CognitoAWSCredentials(COGNITO_IDP_ID, RegionEndpoint.APNortheast1);
  credentials.AddLogin("appleid.apple.com", user.IdToken);

このCredentialをAWS SDKの各サービス用クライアント生成時に使用することで、AWSサービスに設定された権限でアクセスが可能になります。

#注意事項
取得した認証トークンには有効期限があります。
Sign In with Appleで取得できるトークンの期限は10分で、この期限を超えて取得できたトークンを使用するとAWS SDKから、下記のExceptionが発生します。

Amazon.CognitoIdentity.Model.NotAuthorizedException

これをCatchしたら、再ログイン処理を行ってから再試行する、という実装が必要です。

この再ログイン処理ですが、Googole SignInでは、ユーザに再度サインイン画面を表示しなくても、内部でRefreshTokenによるAccess Tokenの再発行が行えます。(Silent SignIn)

しかし、Sign In with Appleでは、Refresh TokenによるAccess Tokenの再発行処理の口がありません。。。
(私が見つけられていないだけかも。。。)

今回私が開発した「LiveCapture3 Remote」では、10分後に再度サインイン画面を表示する、という流れでも特に問題なかったので、そのままにしていますが、もし、Sign In with AppleでのSilent SignInの方法があれば、どなたか教えてください。。

#参考

GoogleアカウントでAWSサービスに接続する
Face IDでログイン!Sign in with AppleをiOSアプリに組み込む
signin with apple 実装するときの注意点まとめ

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?