Självstudie: Logga in användare och anropa Microsoft Graph API från ett Android program

I den här självstudien skapar du en Android app som integreras med Microsofts identitetsplattform för att logga in användare och hämta en åtkomsttoken för att anropa Microsoft Graph API.

När du har slutfört den här självstudien godkänner ditt program inloggningar med personliga Microsoft-konton (inklusive outlook.com, live.com och andra) samt arbets- eller skolkonton från alla företag eller organisationer som använder Azure Active Directory.

I de här självstudierna har du

  • Skapa ett Android appprojekt i Android Studio
  • Registrera appen i Azure Portal
  • Lägga till kod för att stödja användarinloggning och utloggning
  • Lägg till kod för att anropa Microsoft Graph API
  • Testa appen

Förutsättningar

  • Android Studio 3.5+

Så här fungerar den här självstudien

Shows how the sample app generated by this tutorial works

Appen i den här självstudien loggar in användare och hämtar data för deras räkning. Dessa data kommer att nås via ett skyddat API (Microsoft Graph API) som kräver auktorisering och skyddas av Microsofts identitetsplattform.

Mer specifikt:

  • Appen loggar in användaren antingen via en webbläsare eller Microsoft Authenticator och Intune-företagsportal.
  • Slutanvändaren accepterar de behörigheter som programmet har begärt.
  • Din app kommer att utfärdas en åtkomsttoken för Microsoft Graph API.
  • Åtkomsttoken inkluderas i HTTP-begäran till webb-API:et.
  • Bearbeta Svaret från Microsoft Graph.

I det här exemplet används Microsoft Authentication Library for Android (MSAL) för att implementera autentisering: com.microsoft.identity.client.

MSAL förnyar automatiskt token, levererar enkel inloggning (SSO) mellan andra appar på enheten och hanterar kontona.

Den här självstudien visar förenklade exempel på hur du arbetar med MSAL för Android. För enkelhetens skull använder den endast läge för enskilt konto. Om du vill utforska mer komplexa scenarier kan du läsa ett färdigt fungerande kodexempel på GitHub.

Skapa ett projekt

Om du inte redan har ett Android program följer du de här stegen för att konfigurera ett nytt projekt.

  1. Öppna Android Studio och välj Starta ett nytt Android Studio projekt.
  2. Välj Grundläggande aktivitet och välj Nästa.
  3. Namnge ditt program.
  4. Spara paketnamnet. Du kommer att ange den senare i Azure Portal.
  5. Ändra språket från Kotlin till Java.
  6. Ange den lägsta API-nivån till API 19 eller högre och klicka på Slutför.
  7. I projektvyn väljer du Project i listrutan för att visa käll- och icke-källprojektfiler, öppna app/build.gradle och ange targetSdkVersion till 28.

Integrera med Microsofts autentiseringsbibliotek

Registrera ditt program

  1. Logga in på Azure-portalen.

  2. Om du har åtkomst till flera klienter använder du filtret Kataloger + prenumerationer på den översta menyn för att växla till den klientorganisation där du vill registrera programmet.

  3. Sök efter och välj Azure Active Directory.

  4. Under Hantera väljer du Appregistreringar>Ny registrering.

  5. Ange ett namn för ditt program. Användare av din app kan se det här namnet och du kan ändra det senare.

  6. Välj Register (Registrera).

  7. Under Hantera väljer du Autentisering>Lägg till en plattform>Android.

  8. Ange projektets paketnamn. Om du laddade ned koden är com.azuresamples.msalandroidappdet här värdet .

  9. I avsnittet Signaturhash på sidan Konfigurera din Android app väljer du Generera en signaturhash för utveckling. Kopiera sedan kommandot KeyTool som ska användas för din plattform.

    KeyTool.exe installeras som en del av Java Development Kit (JDK). Du måste också installera OpenSSL-verktyget för att köra KeyTool-kommandot. Mer information finns i Android dokumentation om hur du genererar en nyckel.

  10. Ange den signatur-hash som genererats av KeyTool.

  11. Välj Konfigurera och spara MSAL-konfigurationen som visas på konfigurationssidan för Android så att du kan ange den när du konfigurerar appen senare.

  12. Välj Klar.

Konfigurera ditt program

  1. I Android Studio projektfönster går du till app\src\main\res.

  2. Högerklicka på res och välj Ny>katalog. Ange raw som nytt katalognamn och klicka på OK.

  3. I app>src>main>res>raw skapar du en ny JSON-fil med namnet auth_config_single_account.json och klistrar in MSAL-konfigurationen som du sparade tidigare.

    Klistra in under omdirigerings-URI:n:

      "account_mode" : "SINGLE",
    

    Konfigurationsfilen bör likna det här exemplet:

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

    Den här självstudien visar bara hur du konfigurerar en app i läget För enskilt konto. Visa dokumentationen om du vill ha mer information om enstaka eller flera kontolägen och hur du konfigurerar din app

  4. I app>src>main>AndroidManifest.xmllägger du till BrowserTabActivity aktiviteten nedan i programtexten. Med den här posten kan Microsoft anropa ditt program när autentiseringen har slutförts:

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

    Ersätt det paketnamn som du registrerade i Azure Portal med android:host= värdet. Ersätt nyckelhashen som du registrerade i Azure Portal mot android:path= värdet. Signaturhashen ska inte vara URL-kodad. Se till att det finns en inledande / i början av din signaturhash.

    "Paketnamn" som du ersätter android:host värdet med bör se ut ungefär så här: com.azuresamples.msalandroidapp. Signaturhashen som du ersätter värdet android:path med bör se ut ungefär så här: /1wIqXSqBj7w+h11ZifsnqwgyKrY=.

    Du kommer också att kunna hitta dessa värden på bladet Autentisering i din appregistrering. Observera att din omdirigerings-URI ser ut ungefär så här: msauth://com.azuresamples.msalandroidapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D. Signaturhashen är URL-kodad i slutet av det här värdet, men signaturhashen ska inte vara URL-kodad i ditt android:path värde.

Använda MSAL

Lägga till MSAL i projektet

  1. I projektfönstret Android Studio går du till appbuild.gradle> och lägger till följande:

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

    Mer information om Microsoft Graph SDK

Nödvändiga importer

Lägg till följande överst i 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.*;

Instansiera PublicClientApplication

Initiera variabler

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

MainActivity I klassen refererar du till följande onCreate()-metod för att instansiera MSAL med hjälp av 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

Lyssna på knappar och anropa metoder eller loggfel i enlighet med detta.

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

Viktigt

När du loggar ut med MSAL tas all känd information om en användare bort från programmet, men användaren kommer fortfarande att ha en aktiv session på sin enhet. Om användaren försöker logga in igen kan de se inloggningsgränssnittet, men de kanske inte behöver ange sina autentiseringsuppgifter igen eftersom enhetssessionen fortfarande är aktiv.

getAuthInteractiveCallback

Motringning som används för interaktiva begäranden.

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

Motringning används för tysta begäranden

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

Anropa Microsoft Graph API

Följande kod visar hur du anropar GraphAPI med hjälp av 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);
                }
            });
}

Lägga till användargränssnitt

Aktivitet

Om du vill modellera användargränssnittet från den här självstudien tillhandahåller följande metoder en guide för att uppdatera text och lyssna på knappar.

updateUI

Aktivera/inaktivera knappar baserat på inloggningstillstånd och ange text.

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

Metod för att uppdatera text i användargränssnittet för att återspegla utloggning.

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

Layout

Exempelfil activity_main.xml för att visa knappar och textrutor.

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

Testa appen

Lokal körning

Skapa och distribuera appen till en testenhet eller emulator. Du bör kunna logga in och hämta token för Azure AD eller personliga Microsoft-konton.

När du har loggat in visar appen de data som returneras från Microsoft Graph-slutpunkten/me. PR 4

Första gången någon användare loggar in på din app uppmanas de av Microsoft-identiteten att godkänna de begärda behörigheterna. Vissa Azure AD klientorganisationer har inaktiverat användarmedgivande, vilket kräver att administratörer godkänner för alla användares räkning. För att stödja det här scenariot måste du antingen skapa en egen klientorganisation eller få administratörsmedgivande.

Rensa resurser

När det inte längre behövs tar du bort appobjektet som du skapade i steget Registrera ditt program .

Hjälp och support

Om du behöver hjälp, vill rapportera ett problem eller vill lära dig mer om dina supportalternativ kan du läsa Hjälp och support för utvecklare.

Nästa steg

Läs mer om att skapa mobilappar som anropar skyddade webb-API:er i vår scenarioserie i flera delar.