Windows アプリに認証を追加する

概要

このトピックでは、モバイル アプリにクラウド ベースの認証を追加する方法を説明します。 このチュートリアルでは、Azure App Service でサポートされている ID プロバイダーを使用して、Mobile Apps のユニバーサル Windows プラットフォーム (UWP) のクイック スタート プロジェクトに認証を追加します。 Mobile Apps のバックエンドによって正常に認証され、承認されると、ユーザー ID 値が表示されます。

このチュートリアルは、Mobile Apps のクイック スタートに基づいています。 事前に Mobile Apps の使用に関するチュートリアルを完了している必要があります。

アプリケーションを認証に登録し、App Service を構成する

最初に、ID プロバイダーのサイトでアプリを登録する必要があります。その後、プロバイダーによって生成された資格情報を Mobile Apps バックエンドに設定します。

  1. 次のプロバイダー固有の指示に従い、任意の ID プロバイダーを構成します。

  2. アプリ内でサポートするプロバイダーごとに、前の手順を繰り返します。

許可されている外部リダイレクト URL にアプリを追加する

認証をセキュリティで保護するには、アプリ用の新しい URL スキームの定義が必要になります。 これによって、認証プロセスが完了すると認証システムからアプリにリダイレクトできます。 このチュートリアル全体を通して、URL スキーム appname を使用します。 ただし、選択したあらゆる URL スキームを使用できます。 URL スキームは、モバイル アプリに対して一意である必要があります。 サーバー側でリダイレクトを有効にするには、以下の手順に従います。

  1. Azure Portal で、App Service を選択します。

  2. [認証/承認] メニュー オプションをクリックします。

  3. [Allowed External Redirect URLs (許可されている外部リダイレクト URL)]url_scheme_of_your_app://easyauth.callback を入力します。 この文字列の url_scheme_of_your_app は、モバイル アプリケーションの URL スキームです。 プロトコルの通常の URL 仕様 (文字と数字のみを使用し、文字で始まる) に従う必要があります。 数か所で URL スキームに合わせてモバイル アプリケーション コードを調整する必要があるため、選択した文字列をメモしておく必要があります。

  4. [保存] をクリックします。

アクセス許可を、認証されたユーザーだけに制限する

既定では、Mobile Apps バックエンドの API は匿名で呼び出すことができます。 次に、認証されたクライアントのみにアクセスを制限する必要があります。

  • Node.js バックエンド (Azure Portal 経由):

    Mobile Apps の設定で、[ 簡易テーブル ] をクリックし、テーブルを選択します。 [アクセス許可の変更] をクリックし、すべてのアクセス許可に対して [Authenticated access only (認証済みアクセスのみ)] を選択し、[保存] をクリックします。

  • .NET バックエンド (C#):

    サーバープロジェクトで、 Controllers>TodoItemControllerに移動します。 次のように、 [Authorize] 属性を TodoItemController クラスに追加します。 アクセスを特定のメソッドのみに制限するには、この属性を、クラスではなく、そのメソッドのみに適用するだけです。 サーバー プロジェクトを発行します。

      [Authorize]
      public class TodoItemController : TableController<TodoItem>
    
  • Node.js バックエンド (Node.js コード経由) :

    テーブルへのアクセスに対して認証を要求するには、Node.js サーバー スクリプトに次の行を追加します。

      table.access = 'authenticated';
    

    詳細については、「方法: テーブルへのアクセスに認証を要求する」を参照してください。 自社サイトからクイック スタート コード プロジェクトをダウンロードする方法については、「 方法: Git を使用して Node.js バックエンド クイック スタート コード プロジェクトをダウンロードする」を参照してください。

これで、バックエンドへの匿名アクセスが無効になっていることを確認できます。 スタートアップ プロジェクトとして設定された UWP アプリ プロジェクトを使用し、アプリをデプロイして実行します。アプリケーションの開始後、状態コード 401 (許可されていません) のハンドルされない例外が発生することを確認します。 この問題は、認証されていないユーザーとしてアプリケーションがモバイル アプリ コードにアクセスしようとしても、現在の TodoItem テーブルでは認証が要求されるために発生します。

次に、App Service のリソースを要求する前にユーザーを認証するようにアプリケーションを更新します。

アプリケーションに認証を追加する

  1. UWP アプリ プロジェクトの MainPage.xaml.cs ファイルを開き、次のコード スニペットを追加します。

     // Define a member variable for storing the signed-in user. 
     private MobileServiceUser user;
    
     // Define a method that performs the authentication process
     // using a Facebook sign-in. 
     private async System.Threading.Tasks.Task<bool> AuthenticateAsync()
     {
         string message;
         bool success = false;
         try
         {
             // Change 'MobileService' to the name of your MobileServiceClient instance.
             // Sign-in using Facebook authentication.
             user = await App.MobileService
                 .LoginAsync(MobileServiceAuthenticationProvider.Facebook, "{url_scheme_of_your_app}");
             message =
                 string.Format("You are now signed in - {0}", user.UserId);
    
             success = true;
         }
         catch (InvalidOperationException)
         {
             message = "You must log in. Login Required";
         }
    
         var dialog = new MessageDialog(message);
         dialog.Commands.Add(new UICommand("OK"));
         await dialog.ShowAsync();
         return success;
     }
    

    このコードでは、Facebook ログインを使用してユーザーを認証します。 Facebook 以外の ID プロバイダーを使用している場合は、上の MobileServiceAuthenticationProvider の値をプロバイダーに対応する値に変更してください。

  2. MainPage.xaml.cs の OnNavigatedTo() メソッドを置き換えます。 次は、認証をトリガーするアプリに サインイン ボタンを追加します。

     protected override async void OnNavigatedTo(NavigationEventArgs e)
     {
         if (e.Parameter is Uri)
         {
             App.MobileService.ResumeWithURL(e.Parameter as Uri);
         }
     }
    
  3. MainPage.xaml.cs に、次のコード スニペットを追加します。

     private async void ButtonLogin_Click(object sender, RoutedEventArgs e)
     {
         // Login the user and then load data from the mobile app.
         if (await AuthenticateAsync())
         {
             // Switch the buttons and load items from the mobile app.
             ButtonLogin.Visibility = Visibility.Collapsed;
             ButtonSave.Visibility = Visibility.Visible;
             //await InitLocalStoreAsync(); //offline sync support.
             await RefreshTodoItems();
         }
     }
    
  4. MainPage.xaml プロジェクト ファイルを開き、 [保存] ボタンを定義している要素を探して、次のコードに置き換えます。

     <Button Name="ButtonSave" Visibility="Collapsed" Margin="0,8,8,0" 
             Click="ButtonSave_Click">
         <StackPanel Orientation="Horizontal">
             <SymbolIcon Symbol="Add"/>
             <TextBlock Margin="5">Save</TextBlock>
         </StackPanel>
     </Button>
     <Button Name="ButtonLogin" Visibility="Visible" Margin="0,8,8,0" 
             Click="ButtonLogin_Click" TabIndex="0">
         <StackPanel Orientation="Horizontal">
             <SymbolIcon Symbol="Permissions"/>
             <TextBlock Margin="5">Sign in</TextBlock> 
         </StackPanel>
     </Button>
    
  5. App.xaml.cs に、次のコード スニペットを追加します。

     protected override void OnActivated(IActivatedEventArgs args)
     {
         if (args.Kind == ActivationKind.Protocol)
         {
             ProtocolActivatedEventArgs protocolArgs = args as ProtocolActivatedEventArgs;
             Frame content = Window.Current.Content as Frame;
             if (content.Content.GetType() == typeof(MainPage))
             {
                 content.Navigate(typeof(MainPage), protocolArgs.Uri);
             }
         }
         Window.Current.Activate();
         base.OnActivated(args);
     }
    
  6. Package.appxmanifest ファイルを開き、 [宣言] に移動して、[使用可能な宣言] ドロップダウン リストで [プロトコル] を選択し、[追加] ボタンをクリックします。 次に、[プロトコル] 宣言の [プロパティ] を構成します。 [表示名] で、アプリケーションのユーザーに表示する名前を追加します。 [名前] に、自分の {url_scheme_of_your_app} を追加します。

  7. F5 キーを押してアプリを実行します。[サインイン] ボタンをクリックして、選択した ID プロバイダーでアプリにサインインします。 サインインに成功すると、アプリはエラーなしで実行し、バックエンドに対してクエリを行ってデータを更新できるようになります。

クライアント側で認証トークンを保存する

前の例では、標準のサインインを示しました。標準のサインインでは、アプリケーションが開始するたびに、クライアントは ID プロバイダーと App Service の両方にアクセスする必要があります。 この方法は非効率であるだけでなく、多くの顧客が同時にアプリケーションを開始すると、使用率に関連した問題が発生する場合があります。 よって、App Service から返される承認トークンをキャッシュし、最初にその承認トークンの使用を試してから、プロバイダー ベースのサインインを使用するほうが効果的です。

Note

クライアントによって管理される認証とサービスによって管理される認証のどちらを使用する場合でも、App Services が発行したトークンをキャッシュできます。 このチュートリアルでは、サービスによって管理される認証を使用します。

  1. MainPage.xaml.cs プロジェクト ファイルを開き、次の using ステートメントを追加します。

     using System.Linq;        
     using Windows.Security.Credentials;
    
  2. AuthenticateAsync メソッドを次のコードに置き換えます。

     private async System.Threading.Tasks.Task<bool> AuthenticateAsync()
     {
         string message;
         bool success = false;
    
         // This sample uses the Facebook provider.
         var provider = MobileServiceAuthenticationProvider.Facebook;
    
         // Use the PasswordVault to securely store and access credentials.
         PasswordVault vault = new PasswordVault();
         PasswordCredential credential = null;
    
         try
         {
             // Try to get an existing credential from the vault.
             credential = vault.FindAllByResource(provider.ToString()).FirstOrDefault();
         }
         catch (Exception)
         {
             // When there is no matching resource an error occurs, which we ignore.
         }
    
         if (credential != null)
         {
             // Create a user from the stored credentials.
             user = new MobileServiceUser(credential.UserName);
             credential.RetrievePassword();
             user.MobileServiceAuthenticationToken = credential.Password;
    
             // Set the user from the stored credentials.
             App.MobileService.CurrentUser = user;
    
             // Consider adding a check to determine if the token is 
             // expired, as shown in this post: https://aka.ms/jww5vp.
    
             success = true;
             message = string.Format("Cached credentials for user - {0}", user.UserId);
         }
         else
         {
             try
             {
                 // Sign in with the identity provider.
                 user = await App.MobileService
                     .LoginAsync(provider, "{url_scheme_of_your_app}");
    
                 // Create and store the user credentials.
                 credential = new PasswordCredential(provider.ToString(),
                     user.UserId, user.MobileServiceAuthenticationToken);
                 vault.Add(credential);
    
                 success = true;
                 message = string.Format("You are now signed in - {0}", user.UserId);
             }
             catch (MobileServiceInvalidOperationException)
             {
                 message = "You must sign in. Sign-In Required";
             }
         }
    
         var dialog = new MessageDialog(message);
         dialog.Commands.Add(new UICommand("OK"));
         await dialog.ShowAsync();
    
         return success;
     }
    

    この AuthenticateAsync バージョンで、アプリはサービスにアクセスするために、PasswordVault に格納された資格情報の使用を試みます。 保存された資格情報がないときも通常のサインインが実行されます。

    Note

    キャッシュされたトークンは有効期限が切れている場合があります。また、認証後にアプリケーションを使用している際にトークンの期限切れが発生する場合があります。 トークンの期限切れを確認する方法については、有効期限が切れた認証トークンのチェックに関するページを参照してください。 トークンの期限切れに関連する認証エラーを処理するためのソリューションについては、投稿「 Azure Mobile Services マネージド SDK での有効期限切れトークンのキャッシュと処理」を参照してください。

  3. アプリケーションを 2 回再起動します。

    最初の再起動では、プロバイダーによるサインインが再度必要になります。 ただし、2 回目の再起動ではキャッシュされた資格情報が使用され、サインインは回避されます。

次のステップ

これで基本的な認証チュートリアルは完了しましたので、引き続き次のいずれかのチュートリアルのご利用を検討してください。

  • アプリへのプッシュ通知の追加
    アプリにプッシュ通知のサポートを追加して、Azure Notification Hubs を使ってプッシュ通知を送信するようにモバイル アプリ バックエンドを構成する方法について説明します。
  • アプリのオフライン同期の有効化
    モバイル アプリ バックエンドを使用して、オフライン サポートをアプリに追加する方法について説明します。 オフライン同期を使用すると、エンドユーザーは、ネットワークに接続されていなくても、データの表示、追加、変更など、モバイルアプリと対話できます。