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

まとめ

このチュートリアルでは、サポートされている ID プロバイダーを使用して、Android で todolist クイック スタート プロジェクトに認証を追加します。 最初に、このチュートリアルの基になっている Mobile Apps の使用 チュートリアルを完了しておく必要があります。

アプリを認証に登録し、Azure App Services を構成する

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      table.access = 'authenticated';
    

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

  • Android Studio で、Mobile Apps の使用に関するチュートリアルで完成させたプロジェクトを開きます。 [Run (実行)] メニューの [Run app (アプリの実行)] をクリックし、アプリの開始後に、状態コード 401 (許可されていません) のハンドルされない例外が発生することを確認します。

    この例外は、認証されないユーザーとしてアプリがバックエンドにアクセスしようとしても、TodoItem テーブルでは認証が要求されるために発生します。

次に、Mobile Apps バックエンドのリソースを要求する前にユーザーを認証するようにアプリを更新します。

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

  1. Android Studio でプロジェクトを開きます。

  2. Android Studio の Project ExplorerToDoActivity.java ファイルを開き、次の import ステートメントを追加します。

    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.atomic.AtomicBoolean;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.SharedPreferences.Editor;
    
    import com.microsoft.windowsazure.mobileservices.authentication.MobileServiceAuthenticationProvider;
    import com.microsoft.windowsazure.mobileservices.authentication.MobileServiceUser;
    
  3. ToDoActivity クラスに次のメソッドを追加します。

    // You can choose any unique number here to differentiate auth providers from each other. Note this is the same code at login() and onActivityResult().
    public static final int GOOGLE_LOGIN_REQUEST_CODE = 1;
    
    private void authenticate() {
        // Sign in using the Google provider.
        mClient.login(MobileServiceAuthenticationProvider.Google, "{url_scheme_of_your_app}", GOOGLE_LOGIN_REQUEST_CODE);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // When request completes
        if (resultCode == RESULT_OK) {
            // Check the request code matches the one we send in the login request
            if (requestCode == GOOGLE_LOGIN_REQUEST_CODE) {
                MobileServiceActivityResult result = mClient.onActivityResult(data);
                if (result.isLoggedIn()) {
                    // sign-in succeeded
                    createAndShowDialog(String.format("You are now signed in - %1$2s", mClient.getCurrentUser().getUserId()), "Success");
                    createTable();
                } else {
                    // sign-in failed, check the error message
                    String errorMessage = result.getErrorMessage();
                    createAndShowDialog(errorMessage, "Error");
                }
            }
        }
    }
    

    このコードで、Google 認証プロセスを処理するメソッドが作成されます。 ダイアログに認証されたユーザーの ID が表示されます。 認証に成功した場合のみ続行できます。

    注意

    Google 以外の ID プロバイダーを使用している場合は、login メソッドに渡す値を、MicrosoftAccountFacebookTwitterwindowsazureactivedirectory のいずれかに変更します。

  4. onCreate メソッドで、MobileServiceClient オブジェクトをインスタンス化するコードの後に、次のコード行を追加します。

    authenticate();
    

    この呼び出しで、認証プロセスが開始されます。

  5. onCreate メソッドの の後authenticate();に残りのコードを新しい createTable メソッドに移動します。

    private void createTable() {
    
        // Get the table instance to use.
        mToDoTable = mClient.getTable(ToDoItem.class);
    
        mTextNewToDo = (EditText) findViewById(R.id.textNewToDo);
    
        // Create an adapter to bind the items with the view.
        mAdapter = new ToDoItemAdapter(this, R.layout.row_list_to_do);
        ListView listViewToDo = (ListView) findViewById(R.id.listViewToDo);
        listViewToDo.setAdapter(mAdapter);
    
        // Load the items from Azure.
        refreshItemsFromTable();
    }
    
  6. リダイレクトが適切に機能するように、次に示す RedirectUrlActivity のスニペットを AndroidManifest.xml に追加します。

    <activity android:name="com.microsoft.windowsazure.mobileservices.authentication.RedirectUrlActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="{url_scheme_of_your_app}"
                android:host="easyauth.callback"/>
        </intent-filter>
    </activity>
    
  7. redirectUriScheme を Android アプリケーションの build.gradle に追加します。

    android {
        buildTypes {
            release {
                // ...
                manifestPlaceholders = ['redirectUriScheme': '{url_scheme_of_your_app}://easyauth.callback']
            }
            debug {
                // ...
                manifestPlaceholders = ['redirectUriScheme': '{url_scheme_of_your_app}://easyauth.callback']
            }
        }
    }
    
  8. com.android.support:customtabs:23.0.1build.gradle の依存関係に追加します。

    dependencies {
        // ...
        compile 'com.android.support:customtabs:23.0.1'
    }
    
  9. [Run (実行)] メニューの [Run app (アプリの実行)] をクリックしてアプリを開始し、選択した ID プロバイダーでサインインします。

警告

説明されている URL スキームでは、大文字と小文字が区別されます。 {url_scheme_of_you_app} のすべての出現箇所で大文字と小文字を同じように使用してください。

サインインに成功すると、アプリはエラーなしで実行されます。また、バックエンド サービスにクエリを実行したり、データを更新したりできるようになります。

クライアントに認証トークンをキャッシュする

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

注意

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

  1. ToDoActivity.java ファイルを開き、次の import ステートメントを追加します。

    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.SharedPreferences.Editor;
    
  2. 次のメンバーをクラス ToDoActivity クラスに追加します。

    public static final String SHAREDPREFFILE = "temp";
    public static final String USERIDPREF = "uid";
    public static final String TOKENPREF = "tkn";
    
  3. ToDoActivity.java ファイル内で、次の cacheUserToken メソッドの定義を追加します。

    private void cacheUserToken(MobileServiceUser user)
    {
        SharedPreferences prefs = getSharedPreferences(SHAREDPREFFILE, Context.MODE_PRIVATE);
        Editor editor = prefs.edit();
        editor.putString(USERIDPREF, user.getUserId());
        editor.putString(TOKENPREF, user.getAuthenticationToken());
        editor.commit();
    }
    

    このメソッドでは、プライベートとマークされた設定ファイルに、ユーザー ID とトークンを格納します。 これにより、キャッシュへのアクセスが保護され、デバイスの他のアプリケーションはトークンにアクセスできなくなります。 設定は、アプリケーション用にサンドボックス化されます。 ただし、他のユーザーは、デバイスにアクセスできるようになると、他の手段によってトークン キャッシュにアクセスできる可能性があります。

    注意

    トークンによるデータへのアクセスの秘密性が高く、他のユーザーがそのデバイスにアクセスする可能性がある場合は、暗号化によりトークンの保護を強化できます。 ただし、完全に安全なソリューションはこのチュートリアルの範囲を超えており、またセキュリティの要件によって異なります。

  4. ToDoActivity.java ファイル内で、次の loadUserTokenCache メソッドの定義を追加します。

    private boolean loadUserTokenCache(MobileServiceClient client)
    {
        SharedPreferences prefs = getSharedPreferences(SHAREDPREFFILE, Context.MODE_PRIVATE);
        String userId = prefs.getString(USERIDPREF, null);
        if (userId == null)
            return false;
        String token = prefs.getString(TOKENPREF, null);
        if (token == null)
            return false;
    
        MobileServiceUser user = new MobileServiceUser(userId);
        user.setAuthenticationToken(token);
        client.setCurrentUser(user);
    
        return true;
    }
    
  5. ToDoActivity.java ファイルで、authenticate メソッドと onActivityResult メソッドを、トークン キャッシュを使う次のメソッドに置き換えます。 Google 以外のアカウントを使用する場合は、ログイン プロバイダーを変更します。

    private void authenticate() {
        // We first try to load a token cache if one exists.
        if (loadUserTokenCache(mClient))
        {
            createTable();
        }
        // If we failed to load a token cache, sign in and create a token cache
        else
        {
            // Sign in using the Google provider.
            mClient.login(MobileServiceAuthenticationProvider.Google, "{url_scheme_of_your_app}", GOOGLE_LOGIN_REQUEST_CODE);
        }
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // When request completes
        if (resultCode == RESULT_OK) {
            // Check the request code matches the one we send in the sign-in request
            if (requestCode == GOOGLE_LOGIN_REQUEST_CODE) {
                MobileServiceActivityResult result = mClient.onActivityResult(data);
                if (result.isLoggedIn()) {
                    // sign-in succeeded
                    createAndShowDialog(String.format("You are now signed in - %1$2s", mClient.getCurrentUser().getUserId()), "Success");
                    cacheUserToken(mClient.getCurrentUser());
                    createTable();
                } else {
                    // sign-in failed, check the error message
                    String errorMessage = result.getErrorMessage();
                    createAndShowDialog(errorMessage, "Error");
                }
            }
        }
    }
    
  6. アプリケーションをビルドし、有効なアカウントを使用して認証をテストします。 最低 2 回アプリケーションを実行します。 最初の実行で、サインインとトークン キャッシュの作成を求めるプロンプトが表示されます。 それ以降、実行ごとに、認証のためのトークン キャッシュの読み込みが試行されます。 サインインする必要がなくなります。

次のステップ

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

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