Tutorial: Memasukkan pengguna dan memanggil Microsoft Graph API dari aplikasi Android

Dalam tutorial ini, Anda akan membuat aplikasi Android yang terintegrasi dengan platform identitas Microsoft untuk memasukkan pengguna dan mendapatkan token akses untuk memanggil Microsoft Graph API.

Setelah Anda menyelesaikan tutorial ini, aplikasi Anda akan menyetujui aktivitas masuk akun Microsoft pribadi (termasuk outlook.com, live.com, dan lainnya) serta akun kantor atau sekolah dari perusahaan atau organisasi mana pun yang menggunakan Azure Active Directory.

Dalam tutorial ini:

  • Membuat proyek aplikasi Android di Android Studio
  • Mendaftarkan aplikasi di portal Microsoft Azure
  • Menambahkan kode untuk mendukung upaya masuk dan keluar pengguna
  • Menambahkan kode untuk memanggil Microsoft Graph API
  • Menguji aplikasi

Prasyarat

  • Android Studio 3.5+

Cara kerja tutorial ini

Shows how the sample app generated by this tutorial works

Aplikasi dalam tutorial ini akan memasukkan pengguna dan mendapatkan data atas nama mereka. Data ini akan diakses melalui API terproteksi (Microsoft Graph API) yang memerlukan otorisasi dan dilindungi oleh platform identitas Microsoft.

Lebih khusus lagi:

  • Aplikasi Anda akan memasukkan pengguna baik melalui browser atau Microsoft Authenticator dan Intune Company Portal.
  • Pengguna akhir akan menerima izin yang diminta aplikasi Anda.
  • Aplikasi Anda akan diberikan token akses untuk Microsoft Graph API.
  • Token akses akan disertakan dalam permintaan HTTP ke API web.
  • Proses respons Microsoft Graph.

Contoh ini menggunakan Microsoft Authentication Library (MSAL) untuk Android untuk mengimplementasikan Autentikasi: com.microsoft.identity.client.

MSAL akan otomatis memperpanjang token, memberikan akses menyeluruh (SSO) antara aplikasi lain di perangkat, dan mengelola Akun.

Tutorial ini menunjukkan contoh sederhana tentang bekerja dengan MSAL untuk Android. Untuk mempermudah, tutorial ini menggunakan Mode Akun Tunggal saja. Untuk mempelajari skenario yang lebih kompleks, lihat contoh kode kerja yang telah selesai di GitHub.

Membuat proyek

Jika Anda belum memiliki aplikasi Android, ikuti langkah-langkah ini untuk menyiapkan proyek baru.

  1. Buka Android Studio, dan pilih Mulai proyek Android Studio baru.
  2. Pilih Aktivitas Dasar dan pilih Berikutnya.
  3. Beri nama aplikasi Anda.
  4. Simpan nama paket. Anda akan memasukkannya ke portal Microsoft Azure di lain waktu.
  5. Ubah bahasa pemrogram dari Kotlin ke Java.
  6. Atur Tingkat API minimum ke API 19 atau lebih tinggi, dan klik Selesai.
  7. Di tampilan proyek, pilih Proyek di menu drop-down untuk menampilkan file proyek sumber dan non-sumber, buka app/build.gradle dan atur targetSdkVersion ke 28.

Integrasi dengan Microsoft Authentication Library

Mendaftarkan aplikasi

  1. Masuk ke portal Microsoft Azure.

  2. Jika Anda memiliki akses ke beberapa penyewa, gunakan filter Direktori + langganan di menu atas untuk beralih penyewa aplikasinya ingin Anda daftarkan.

  3. Cari dan pilih Microsoft Azure Active Directory.

  4. Di bagian Kelola, pilih Pendaftaran aplikasi>Pendaftaran baru.

  5. Masukkan Nama untuk aplikasi Anda. Pengguna aplikasi mungkin melihat nama ini, dan Anda dapat mengubahnya nanti.

  6. Pilih Daftarkan.

  7. Di bagian Kelola, pilih Autentikasi>Tambahkan platform>Android.

  8. Masukkan Nama Paket proyek. Jika Anda mengunduh kode, nilai ini adalah com.azuresamples.msalandroidapp.

  9. Di bagian Hash tanda tangan di halaman Konfigurasi aplikasi Android Anda, pilih Menghasilkan Hash Tanda Tangan pengembangan. dan salin perintah KeyTool untuk digunakan untuk platform Anda.

    KeyTool.exe diinstal sebagai bagian dari Java Development Kit (JDK). Anda juga harus menginstal alat OpenSSL untuk menjalankan perintah KeyTool. Lihat dokumentasi Android tentang menghasilkan kunci untuk mendapatkan informasi selengkapnya.

  10. Masukkan Hash tanda tangan yang dihasilkan oleh KeyTool.

  11. Pilih Konfigurasi dan simpan Konfigurasi MSAL yang muncul di halaman Konfigurasi Android agar Anda dapat memasukkannya saat mengonfigurasi aplikasi di lain waktu.

  12. Pilih Selesai.

Mengonfigurasi aplikasi klien

  1. Di panel proyek Android Studio, buka app\src\main\res.

  2. Klik kanan res dan pilih Direktori>Baru. Masukkan raw sebagai nama direktori baru dan klik OK.

  3. Dalam app>src>main>res>raw, buat file JSON baru bernama auth_config_single_account.json dan tempel MSAL Configuration yang sudah Anda simpan sebelumnya.

    Di bawah URI pengalihan, tempel:

      "account_mode" : "SINGLE",
    

    File config harus menyerupai contoh ini:

    {
      "client_id" : "0984a7b6-bc13-4141-8b0d-8f767e136bb7",
      "authorization_user_agent" : "DEFAULT",
      "redirect_uri" : "msauth://com.azuresamples.msalandroidapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D",
      "broker_redirect_uri_registered" : true,
      "account_mode" : "SINGLE",
      "authorities" : [
        {
          "type": "AAD",
          "audience": {
            "type": "AzureADandPersonalMicrosoftAccount",
            "tenant_id": "common"
          }
        }
      ]
    }
    

    Tutorial ini hanya menunjukkan cara mengonfigurasi aplikasi dalam mode Akun Tunggal. Lihat dokumentasi untuk informasi selengkapnya tentang mode satu vs. beberapa akun dan mengonfigurasi aplikasi Anda

  4. Dalam app>src>main>AndroidManifest.xml, tambahkan aktivitas BrowserTabActivity di bawah ke bodi aplikasi. Entri ini memungkinkan Microsoft memanggil kembali ke aplikasi Anda setelah selesai autentikasi:

    <!--Intent filter to capture System Browser or Authenticator calling back to our app after sign-in-->
    <activity
        android:name="com.microsoft.identity.client.BrowserTabActivity">
        <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="msauth"
                android:host="Enter_the_Package_Name"
                android:path="/Enter_the_Signature_Hash" />
        </intent-filter>
    </activity>
    

    Ganti nama paket yang Anda daftarkan di portal Microsoft Azure untuk nilai android:host= tersebut. Ganti hash kunci yang Anda daftarkan di portal Microsoft Azure untuk nilai android:path= tersebut. Hash Tanda Tangan tidak boleh dikodekan URL. Pastikan ada / terdepan di awal Hash Tanda Tangan Anda.

    "Nama Paket" yang akan Anda ganti dengan nilai android:host akan terlihat mirip dengan: com.azuresamples.msalandroidapp. "Hash Tanda Tangan" yang akan Anda ganti dengan nilai android:path akan terlihat mirip dengan: /1wIqXSqBj7w+h11ZifsnqwgyKrY=.

    Anda juga dapat menemukan nilai-nilai ini di bilah Autentikasi pendaftaran aplikasi Anda. Perhatikan bahwa URI pengalihan Anda akan terlihat mirip dengan: msauth://com.azuresamples.msalandroidapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D. Meskipun Hash Tanda Tangan dikodekan URL di akhir nilai ini, Hash Tanda Tangan tidak boleh dikodekan URL dalam nilai android:path Anda.

Menggunakan MSAL

Menambahkan MSAL ke proyek Anda

  1. Di jendela proyek Android Studio, navigasi ke app>build.gradle dan tambahkan yang berikut:

    apply plugin: 'com.android.application'
    
    allprojects {
     repositories {
        mavenCentral()
        google()
        mavenLocal()
        maven {
            url 'https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1'
        }
        maven {
            name "vsts-maven-adal-android"
            url "https://identitydivision.pkgs.visualstudio.com/_packaging/AndroidADAL/maven/v1"
            credentials {
                username System.getenv("ENV_VSTS_MVN_ANDROIDADAL_USERNAME") != null ? System.getenv("ENV_VSTS_MVN_ANDROIDADAL_USERNAME") : project.findProperty("vstsUsername")
                password System.getenv("ENV_VSTS_MVN_ANDROIDADAL_ACCESSTOKEN") != null ? System.getenv("ENV_VSTS_MVN_ANDROIDADAL_ACCESSTOKEN") : project.findProperty("vstsMavenAccessToken")
            }
        }
        jcenter()
     }
    }
    dependencies{
     implementation 'com.microsoft.identity.client:msal:2.+'
     implementation 'com.microsoft.graph:microsoft-graph:1.5.+'
     }
    packagingOptions{
     exclude("META-INF/jersey-module-version")
    }
    

    Selengkapnya tentang Microsoft Graph SDK

Impor yang Diperlukan

Tambahkan berikut di atas app>src>main>java>com.example(aplikasianda)>MainActivity.java

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.JsonObject;
import com.microsoft.graph.authentication.IAuthenticationProvider; //Imports the Graph sdk Auth interface
import com.microsoft.graph.concurrency.ICallback;
import com.microsoft.graph.core.ClientException;
import com.microsoft.graph.http.IHttpRequest;
import com.microsoft.graph.models.extensions.*;
import com.microsoft.graph.requests.extensions.GraphServiceClient;
import com.microsoft.identity.client.AuthenticationCallback; // Imports MSAL auth methods
import com.microsoft.identity.client.*;
import com.microsoft.identity.client.exception.*;

Menginisiasi PublicClientApplication

Menginisialisasi Variabel

private final static String[] SCOPES = {"Files.Read"};
/* Azure AD v2 Configs */
final static String AUTHORITY = "https://login.microsoftonline.com/common";
private ISingleAccountPublicClientApplication mSingleAccountApp;

private static final String TAG = MainActivity.class.getSimpleName();

/* UI & Debugging Variables */
Button signInButton;
Button signOutButton;
Button callGraphApiInteractiveButton;
Button callGraphApiSilentButton;
TextView logTextView;
TextView currentUserTextView;

onCreate

Di dalam kelas MainActivity, lihat metode onCreate() berikut untuk menginisiasi MSAL menggunakan SingleAccountPublicClientApplication.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    initializeUI();

    PublicClientApplication.createSingleAccountPublicClientApplication(getApplicationContext(),
            R.raw.auth_config_single_account, new IPublicClientApplication.ISingleAccountApplicationCreatedListener() {
                @Override
                public void onCreated(ISingleAccountPublicClientApplication application) {
                    mSingleAccountApp = application;
                    loadAccount();
                }
                @Override
                public void onError(MsalException exception) {
                    displayError(exception);
                }
            });
}

loadAccount

//When app comes to the foreground, load existing account to determine if user is signed in
private void loadAccount() {
    if (mSingleAccountApp == null) {
        return;
    }

    mSingleAccountApp.getCurrentAccountAsync(new ISingleAccountPublicClientApplication.CurrentAccountCallback() {
        @Override
        public void onAccountLoaded(@Nullable IAccount activeAccount) {
            // You can use the account data to update your UI or your app database.
            updateUI(activeAccount);
        }

        @Override
        public void onAccountChanged(@Nullable IAccount priorAccount, @Nullable IAccount currentAccount) {
            if (currentAccount == null) {
                // Perform a cleanup task as the signed-in account changed.
                performOperationOnSignOut();
            }
        }

        @Override
        public void onError(@NonNull MsalException exception) {
            displayError(exception);
        }
    });
}

initializeUI

Dengarkan tombol dan gunakan metode atau catat kesalahan masing-masing.

private void initializeUI(){
        signInButton = findViewById(R.id.signIn);
        callGraphApiSilentButton = findViewById(R.id.callGraphSilent);
        callGraphApiInteractiveButton = findViewById(R.id.callGraphInteractive);
        signOutButton = findViewById(R.id.clearCache);
        logTextView = findViewById(R.id.txt_log);
        currentUserTextView = findViewById(R.id.current_user);

        //Sign in user
        signInButton.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v) {
                if (mSingleAccountApp == null) {
                    return;
                }
                mSingleAccountApp.signIn(MainActivity.this, null, SCOPES, getAuthInteractiveCallback());
            }
        });

        //Sign out user
        signOutButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mSingleAccountApp == null){
                    return;
                }
                mSingleAccountApp.signOut(new ISingleAccountPublicClientApplication.SignOutCallback() {
                    @Override
                    public void onSignOut() {
                        updateUI(null);
                        performOperationOnSignOut();
                    }
                    @Override
                    public void onError(@NonNull MsalException exception){
                        displayError(exception);
                    }
                });
            }
        });

        //Interactive
        callGraphApiInteractiveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mSingleAccountApp == null) {
                    return;
                }
                mSingleAccountApp.acquireToken(MainActivity.this, SCOPES, getAuthInteractiveCallback());
            }
        });

        //Silent
        callGraphApiSilentButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mSingleAccountApp == null){
                    return;
                }
                mSingleAccountApp.acquireTokenSilentAsync(SCOPES, AUTHORITY, getAuthSilentCallback());
            }
        });
    }

Penting

Keluar dengan MSAL akan menghapus semua informasi yang diketahui tentang pengguna dari aplikasi, tetapi pengguna akan tetap memiliki sesi yang aktif di perangkatnya. Jika pengguna mencoba masuk lagi, mereka mungkin melihat UI masuk, tetapi mungkin tidak perlu memasukkan kembali kredensial mereka karena sesi perangkat masih aktif.

getAuthInteractiveCallback

Callback yang digunakan untuk permintaan interaktif.

private AuthenticationCallback getAuthInteractiveCallback() {
    return new AuthenticationCallback() {
        @Override
        public void onSuccess(IAuthenticationResult authenticationResult) {
            /* Successfully got a token, use it to call a protected resource - MSGraph */
            Log.d(TAG, "Successfully authenticated");
            /* Update UI */
            updateUI(authenticationResult.getAccount());
            /* call graph */
            callGraphAPI(authenticationResult);
        }

        @Override
        public void onError(MsalException exception) {
            /* Failed to acquireToken */
            Log.d(TAG, "Authentication failed: " + exception.toString());
            displayError(exception);
        }
        @Override
        public void onCancel() {
            /* User canceled the authentication */
            Log.d(TAG, "User cancelled login.");
        }
    };
}

getAuthSilentCallback

Callback yang digunakan untuk permintaan senyap

private SilentAuthenticationCallback getAuthSilentCallback() {
    return new SilentAuthenticationCallback() {
        @Override
        public void onSuccess(IAuthenticationResult authenticationResult) {
            Log.d(TAG, "Successfully authenticated");
            callGraphAPI(authenticationResult);
        }
        @Override
        public void onError(MsalException exception) {
            Log.d(TAG, "Authentication failed: " + exception.toString());
            displayError(exception);
        }
    };
}

Memanggil Microsoft Graph API

Kode berikut menunjukkan cara memanggil GraphAPI menggunakan Graph SDK.

callGraphAPI

private void callGraphAPI(IAuthenticationResult authenticationResult) {

    final String accessToken = authenticationResult.getAccessToken();

    IGraphServiceClient graphClient =
            GraphServiceClient
                    .builder()
                    .authenticationProvider(new IAuthenticationProvider() {
                        @Override
                        public void authenticateRequest(IHttpRequest request) {
                            Log.d(TAG, "Authenticating request," + request.getRequestUrl());
                            request.addHeader("Authorization", "Bearer " + accessToken);
                        }
                    })
                    .buildClient();
    graphClient
            .me()
            .drive()
            .buildRequest()
            .get(new ICallback<Drive>() {
                @Override
                public void success(final Drive drive) {
                    Log.d(TAG, "Found Drive " + drive.id);
                    displayGraphResult(drive.getRawObject());
                }

                @Override
                public void failure(ClientException ex) {
                    displayError(ex);
                }
            });
}

Menambahkan UI

Aktivitas

Jika Anda ingin memodelkan UI di luar tutorial ini, metode berikut menyediakan panduan untuk memperbarui teks dan mendengarkan tombol.

updateUI

Aktifkan/nonaktifkan tombol berdasarkan status masuk dan atur teks.

private void updateUI(@Nullable final IAccount account) {
    if (account != null) {
        signInButton.setEnabled(false);
        signOutButton.setEnabled(true);
        callGraphApiInteractiveButton.setEnabled(true);
        callGraphApiSilentButton.setEnabled(true);
        currentUserTextView.setText(account.getUsername());
    } else {
        signInButton.setEnabled(true);
        signOutButton.setEnabled(false);
        callGraphApiInteractiveButton.setEnabled(false);
        callGraphApiSilentButton.setEnabled(false);
        currentUserTextView.setText("");
        logTextView.setText("");
    }
}

displayError

private void displayError(@NonNull final Exception exception) {
       logTextView.setText(exception.toString());
   }

displayGraphResult

private void displayGraphResult(@NonNull final JsonObject graphResponse) {
      logTextView.setText(graphResponse.toString());
  }

performOperationOnSignOut

Metode untuk memperbarui teks di UI untuk mencerminkan proses keluar.

private void performOperationOnSignOut() {
    final String signOutText = "Signed Out.";
    currentUserTextView.setText("");
    Toast.makeText(getApplicationContext(), signOutText, Toast.LENGTH_SHORT)
            .show();
}

Layout

Contoh file activity_main.xml menampilkan tombol dan kotak teks.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:paddingTop="5dp"
        android:paddingBottom="5dp"
        android:weightSum="10">

        <Button
            android:id="@+id/signIn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="5"
            android:gravity="center"
            android:text="Sign In"/>

        <Button
            android:id="@+id/clearCache"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="5"
            android:gravity="center"
            android:text="Sign Out"
            android:enabled="false"/>

    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">

        <Button
            android:id="@+id/callGraphInteractive"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="5"
            android:text="Get Graph Data Interactively"
            android:enabled="false"/>

        <Button
            android:id="@+id/callGraphSilent"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="5"
            android:text="Get Graph Data Silently"
            android:enabled="false"/>
    </LinearLayout>

    <TextView
        android:text="Getting Graph Data..."
        android:textColor="#3f3f3f"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:id="@+id/graphData"
        android:visibility="invisible"/>

    <TextView
        android:id="@+id/current_user"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="20dp"
        android:layout_weight="0.8"
        android:text="Account info goes here..." />

    <TextView
        android:id="@+id/txt_log"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="20dp"
        android:layout_weight="0.8"
        android:text="Output goes here..." />
</LinearLayout>

Menguji aplikasi Anda

Jalankan secara lokal

Buat dan sebarkan aplikasi ke perangkat pengujian atau emulator. Anda harus bisa masuk dan mendapatkan token untuk akun Microsoft Azure AD atau Microsoft pribadi.

Setelah Anda masuk, aplikasi akan menampilkan data yang ditampilkan dari titik akhir /me Microsoft Graph. PR 4

Saat pengguna masuk ke aplikasi untuk pertama kali, mereka akan diminta oleh identitas Microsoft untuk menyetujui izin yang diminta. Beberapa penyewa Microsoft Azure AD telah menonaktifkan persetujuan pengguna yang mengharuskan admin memberikan persetujuan atas nama semua pengguna. Untuk mendukung skenario ini, Anda harus membuat penyewa Anda sendiri atau menerima persetujuan admin.

Membersihkan sumber daya

Jika tidak diperlukan lagi, hapus objek aplikasi yang dibuat pada langkah Mendaftarkan aplikasi.

Bantuan dan dukungan

Jika Anda memerlukan bantuan, ingin melaporkan masalah, atau ingin mempelajari opsi dukungan, lihat Bantuan dan dukungan bagi pengembang.

Langkah berikutnya

Pelajari selengkapnya tentang cara membangun aplikasi seluler yang memanggil API web yang dilindungi dalam seri skenario multi-bagian kami.