Zelfstudie: Gebruikers aanmelden en de Microsoft Graph API aanroepen vanuit een Android-app

In deze zelfstudie bouwt u een Android-app die kan worden geïntegreerd met het Microsoft-identiteitsplatform om gebruikers aan te melden en een toegangs token op te halen om de api Microsoft Graph aan te roepen.

Wanneer u de zelfstudie hebt voltooid, accepteert uw toepassing aanmeldingen van persoonlijke Microsoft-accounts (waaronder outlook.com, live.com en overige accounts), maar ook werk- of schoolaccounts van elk bedrijf of elke organisatie waar Azure Active Directory wordt gebruikt.

In deze zelfstudie hebt u het volgende gedaan:

  • Een Android-app-project maken in Android Studio
  • De app registreren in de Azure-portal
  • Code toevoegen voor de ondersteuning van het aan- en afmelden van gebruikers
  • Code toevoegen om de Microsoft Graph API aan te roepen
  • De app testen

Vereisten

  • Android Studio 3.5+

Hoe deze zelfstudie werkt

Er wordt getoond hoe de voorbeeld-app werkt die wordt gegenereerd in deze zelfstudie

Met de app in deze zelfstudie worden gebruikers aangemeld, en worden namens hen gegevens opgehaald. Deze gegevens worden geopend via een beveiligde API (Microsoft Graph API), waarvoor autorisatie is vereist en die is beveiligd met Microsoft Identity Platform.

Met name:

  • Met uw app wordt de gebruiker aangemeld via een browser of via Microsoft Authenticator en Intune-bedrijfsportal.
  • De eindgebruiker accepteert de machtigingen die met de toepassing zijn aangevraagd.
  • Aan de app wordt een toegangstoken verleend voor de Microsoft Graph API.
  • Het toegangstoken is opgenomen in de HTTP-aanvraag voor de web-API.
  • Verwerk het Microsoft Graph-antwoord.

In dit voorbeeld wordt de Microsoft Authentication Library for Android (MSAL) gebruikt voor het implementeren van Verificatie: com.microsoft.identity.client.

In MSAL worden tokens automatisch vernieuwd, eenmalige aanmelding (SSO) geboden tussen andere apps op het apparaat, en de accounts beheerd.

In deze zelfstudie worden vereenvoudigde voorbeelden getoond van het werken met MSAL for Android. Ter vereenvoudiging wordt in deze zelfstudie alleen gebruik gemaakt van de modus voor een enkele account. Als u meer complexe scenario's wilt verkennen, raadpleegt u een voltooid voorbeeld van werkende code op GitHub.

Een project maken

Als u nog geen Android-toepassing hebt, volgt u de volgende stappen om een nieuw project in te stellen.

  1. Open Android Studio en selecteer Een nieuw Android Studio-project starten.
  2. Selecteer Basisactiviteit en selecteer Volgende.
  3. Geef uw toepassing een naam.
  4. Sla de naam van het pakket op. U gaat deze later in Azure Portal invoeren.
  5. Wijzig de taal van Kotlin in Java.
  6. Stel het minimale API-niveau in op API 19 of hoger en klik op Voltooien.
  7. Kies in de projectweergave Project in de vervolgkeuzelijst om bron- en niet-bronprojectbestanden weer te geven, open app/build.gradle en stel targetSdkVersion in op 28.

Integreren met de Microsoft Authentication Library

Uw toepassing registreren

  1. Meld u aan bij de Azure-portal.

  2. Als u toegang hebt tot meerdere tenants, gebruikt u het filter Directory + abonnement in het bovenste menu om de tenant te selecteren waarin u een toepassing wilt registreren.

  3. Zoek en selecteer de optie Azure Active Directory.

  4. Selecteer onder Beheren de optie App-registraties > Nieuwe registratie.

  5. Voer een Naam in voor de toepassing. Gebruikers van uw app kunnen de naam zien. U kunt deze later wijzigen.

  6. Selecteer Registreren.

  7. Selecteer onder Beheren achtereenvolgens Verificatie > Een platform toevoegen > Android.

  8. Voer de pakketnaam van het project in. Als u de code hebt gedownload, is deze waarde com.azuresamples.msalandroidapp.

  9. Selecteer in de sectie Handtekening-hash van de pagina Uw Android-app configureren de optie Een handtekening-hash voor de ontwikkeling genereren. en kopieer de KeyTool-opdracht die u wilt gebruiken voor uw platform.

    KeyTool.exe is geïnstalleerd als onderdeel van de JDK (Java Development Kit). U moet ook het OpenSSL-hulpprogramma installeren om de KeyTool-opdracht uit te voeren. Raadpleeg de Android-documentatie over het genereren van een sleutel voor meer informatie.

  10. Voer de handtekening-hash in die is gegenereerd door KeyTool.

  11. Selecteer Configureren en sla de MSAL-configuratie op die wordt weergegeven op de pagina Android-configuratie, zodat u deze kunt invoeren wanneer u de app later configureert.

  12. Selecteer Gereed.

Uw toepassing configureren

  1. Ga in het projectdeelvenster van Android Studio naar app\src\main\res.

  2. Klik met de rechtermuisknop op res en kies Nieuw > Map. Voer raw in als de naam van de nieuwe map en klik op OK.

  3. Maak in app > src > main > res > raw een nieuw JSON-bestand met de naam auth_config_single_account.json en plak de MSAL-configuratie die u eerder hebt opgeslagen.

    Plak deze onder de omleidings-URI:

      "account_mode" : "SINGLE",
    

    Het configuratiebestand moet er als volgt uitzien:

    {
      "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"
          }
        }
      ]
    }
    

    In deze zelfstudie wordt alleen getoond hoe u een app kunt configureren in de modus voor één account. Raadpleeg de documentatie voor meer informatie over modus voor één account versus de modus voor meerdere accounts en het configureren van uw app

  4. Voeg in app > src > main > AndroidManifest.xml, de onderstaande BrowserTabActivity-activiteit toe aan de hoofdtekst van de toepassing. Met deze vermelding kan Microsoft uw toepassing weer aanroepen wanneer de verificatie is voltooid:

    <!--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>
    

    Vervang de naam van het pakket dat u hebt geregistreerd in Azure Portal door de waarde android:host=. Vervang de sleutel-hash die u hebt geregistreerd in Azure Portal door de waarde android:path=. De handtekening-hash mag niet als URL zijn gecodeerd. Zorg ervoor dat er een voorloop-/ staat aan het begin van uw handtekening-hash.

    De pakketnaam waar u de waarde door vervangt, moet er ongeveer als volgt android:host uitzien: com.azuresamples.msalandroidapp. De 'Signature Hash' waar u uw waarde door vervangt, moet er ongeveer als volgt android:path uitzien: /1wIqXSqBj7w+h11ZifsnqwgyKrY=.

    U kunt deze waarden ook vinden op de blade Verificatie van uw app-registratie. Merk op dat uw omleidings-URI er ongeveer als volgt uitziet: msauth://com.azuresamples.msalandroidapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D. Als de handtekening-hash als URL is gecodeerd aan het einde van deze waarde, mag de handtekening-hash niet als URL zijn gecodeerd in uw waarde android:path.

MSAL gebruiken

MSAL toevoegen aan uw project

  1. Ga in Android Studio projectvenster naar app > build.gradle en voeg het volgende toe:

    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")
    }
    

    Meer informatie over de Microsoft Graph-SDK

Vereiste imports

Voeg het volgende toe bovenaan app > src > main> java > com.example(yourapp) > 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.*;

PublicClientApplication instantiëren

Variabelen initialiseren

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

In de klasse MainActivity raadpleegt u de volgende onCreate()-methode om MSAL te instantiëren met behulp van de 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

Luister dienovereenkomstig naar knoppen- en oproepmethoden of logboekfouten.

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());
            }
        });
    }

Belangrijk

Bij afmelden met MSAL wordt alle bekende informatie over een gebruiker verwijderd uit de toepassing. De gebruiker beschikt dan nog steeds over een actieve sessie op het apparaat. Als de gebruiker zich opnieuw probeert aan te melden, ziet deze mogelijk de gebruikersinterface voor aanmelden, maar hoeft de gebruiker mogelijk niet opnieuw referenties op te geven, omdat de sessie van het apparaat nog steeds actief is.

getAuthInteractiveCallback

Callback die wordt gebruikt voor interactieve aanvragen.

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 die wordt gebruikt voor aanvragen op de achtergrond

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);
        }
    };
}

Microsoft Graph API aanroepen

De volgende code laat zien hoe u de GraphAPI aanroept met de 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);
                }
            });
}

Gebruikersinterface toevoegen

Activiteit

Als u uw gebruikersinterface wilt modelleren buiten deze zelfstudie om, bieden de volgende methoden aanwijzingen voor het bijwerken van tekst en het luisteren naar knoppen.

updateUI

Knoppen in- of uitschakelen op basis van de aanmeldingsstatus en tekst instellen.

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

Methode voor het bijwerken van de tekst in de gebruikersinterface om afmelden weer te geven.

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

Layout

Voorbeeldbestand activity_main.xml om knoppen en tekstvakken weer te geven.

<?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>

Uw app testen

Lokaal uitvoeren

Compileer en implementeer de app op een testapparaat of emulator. U moet zich kunnen aanmelden en tokens ontvangen voor Azure AD of persoonlijke Microsoft-accounts.

Nadat u zich hebt aangemeld, verschijnen in de app de gegevens die zijn geretourneerd via het Microsoft Graph /me-eindpunt. PR 4

De eerste keer dat een gebruiker zich aanmeldt bij uw app, wordt door Microsoft gevraagd toestemming te geven voor de aangevraagde machtigingen. Voor sommige Azure AD-tenants is gebruikerstoestemming uitgeschakeld. In dit geval moeten beheerders toestemming geven namens alle gebruikers. Ter ondersteuning van dit scenario moet u uw eigen tenant maken of toestemming van de beheerder krijgen.

Resources opschonen

Verwijder het app-object dat u hebt gemaakt in de stap Uw toepassing registreren als u het niet meer nodig hebt.

Help en ondersteuning

Als u hulp nodig hebt, een probleem wilt melden of meer informatie wilt over uw ondersteuningsopties, raadpleegt u Hulp en ondersteuning voor ontwikkelaars.

Volgende stappen

Meer informatie over het bouwen van mobiele apps die beveiligde web-API's aanroepen in onze reeks met meerdere scenario's.