Oktatóanyag: Felhasználók bejelentkezése és a Microsoft Graph API hívása Android-alkalmazásból

Ebben az oktatóanyagban olyan Android-alkalmazást hoz létre, amely integrálható a Microsoft Identitásplatform-sel a felhasználók bejelentkeztetése és a Microsoft Graph API-t hívó hozzáférési jogkivonat beszerzése érdekében.

Az oktatóanyag befejezése után az alkalmazás elfogadja a személyes Microsoft-fiókok (például outlook.com, live.com stb.) bejelentkezését, valamint bármely, az alkalmazást használó vállalat vagy szervezet munkahelyi vagy iskolai Azure Active Directory.

Ebben az oktatóanyagban:

  • Android-alkalmazásprojekt létrehozása a Android Studio
  • Az alkalmazás regisztrálása a Azure Portal
  • Kód hozzáadása a felhasználói bejelentkezés és kijelentkezás támogatásához
  • A Microsoft Graph API-t Graph kód hozzáadása
  • Az alkalmazás tesztelése

Előfeltételek

  • Android Studio 3.5+

Az oktatóanyag működése

Bemutatja, hogyan működik az oktatóanyag által létrehozott mintaalkalmazás

Az oktatóanyagban az alkalmazás bejelentkezik a felhasználókba, és lekért adatokat a nevükben. Ezek az adatok egy olyan védett API-n (Microsoft Graph API-n) keresztül érhetők el, amely engedélyezést igényel, és az adatok védelmét a Microsoft Identitásplatform.

Pontosabban:

  • Az alkalmazás egy böngészőben vagy a böngészőben, vagy a Microsoft Authenticator és Intune Céges portál.
  • A végfelhasználó elfogadja az alkalmazás által kért engedélyeket.
  • Az alkalmazás hozzáférési jogkivonatot fog kiadni a Microsoft Graph API-hoz.
  • A hozzáférési jogkivonat szerepelni fog a webes API-hoz való HTTP-kérésben.
  • A Microsoft által Graph feldolgozása.

Ez a minta az Androidhoz készült Microsoft Authentication Library (MSAL) használatával valósítja meg a hitelesítést: com.microsoft.identity.client.

Az MSAL automatikusan megújítja a jogkivonatokat, egyszeri bejelentkezést (SSO) kézbesít az eszközön található más alkalmazások között, és kezeli a fióko(k)t.

Ez az oktatóanyag az Androidhoz készült MSAL-sel való munkavégzés egyszerűsített példáit mutatja be. Az egyszerűség kedvéért csak az egyfiókos módot használja. Összetettebb forgatókönyvek megismeréséhez tekintse meg a befejezett munkakódmintát a GitHub.

Projekt létrehozása

Ha még nem rendelkezik Android-alkalmazással, kövesse az alábbi lépéseket egy új projekt beállításához.

  1. Nyissa Android Studio, majd válassza a Start a new Android Studio project (Új projekt Android Studio) lehetőséget.
  2. Válassza az Alapszintű tevékenység, majd a Tovább lehetőséget.
  3. Adjon nevet az alkalmazásnak.
  4. Mentse a csomag nevét. Ezt később fogja beírni a Azure Portal.
  5. Módosítsa a nyelvet Kotlinról Java nyelvre.
  6. Állítsa a Minimális API-szintet API 19-re vagy magasabbra, majd kattintson a Finish (Befejezés) gombra.
  7. A projektnézetben válassza a Project a legördülő menüben a forrás- és nem forrásprojektfájlok megjelenítéséhez, nyissa meg az app/build.gradle fájlt, és állítsa a következőre: targetSdkVersion 28 .

Integráció a Microsoft Authentication Libraryvel

Az alkalmazás regisztrálása

  1. Jelentkezzen be az Azure Portalra.

  2. Ha több bérlőhöz is hozzáféréssel rendelkezik, a felső menü Címtár és előfizetés szűrője segítségével válassza ki azt a bérlőt, amelyben regisztrálni szeretné az alkalmazást.

  3. Keresse meg és válassza ki az Azure Active Directoryt.

  4. A Kezelés alatt válassza a Alkalmazásregisztrációk > lehetőséget.

  5. Adja meg az alkalmazás nevét. Előfordulhat, hogy az alkalmazás felhasználói látják ezt a nevet, és később módosíthatja.

  6. Válassza a Regisztráció lehetőséget.

  7. A Kezelés alatt válassza a Hitelesítés Android platform > hozzáadása > lehetőséget.

  8. Adja meg a projekt Package Name (Csomag neve) nevét. Ha letöltötte a kódot, ez az érték com.azuresamples.msalandroidapp .

  9. Az Android-alkalmazás konfigurálása oldal Aláírás-kivonat szakaszában válassza a Fejlesztési aláírás-kivonat létrehozása lehetőséget. másolja ki a KeyTool parancsot a platformhoz való használathoz.

    KeyTool.exe a Java fejlesztői készlet (JDK) részeként van telepítve. A KeyTool parancs végrehajtásához az OpenSSL eszközt is telepítenie kell. További információért tekintse meg a kulcs létrehozásáról készült Android-dokumentációt.

  10. Adja meg a KeyTool által létrehozott aláírás-kivonatot.

  11. Válassza a Konfigurálás lehetőséget, és mentse az Android konfigurációs oldalán megjelenő MSAL-konfigurációt, hogy később az alkalmazás konfigurálásakor meg tudja azt adnia.

  12. Válassza a Kész lehetőséget.

Az alkalmazás konfigurálása

  1. A Android Studio panelen lépjen az app\src\main\res mappára.

  2. Kattintson a jobb gombbal a res elemre, és válassza az Új címtár > lehetőséget. Adja raw meg a nevet az új könyvtár neveként, majd kattintson az OK gombra.

  3. Az app > src main res raw fájlban hozzon létre egy nevű új JSON-fájlt, és illessze be > > > a korábban auth_config_single_account.json mentett MSAL-konfigurációt.

    Az átirányítási URI alá illessze be a következőt:

      "account_mode" : "SINGLE",
    

    A konfigurációs fájlnak az alábbi példához hasonlónak kell lennie:

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

    Ez az oktatóanyag csak azt mutatja be, hogyan konfigurálható egyalkalmazás egyfiókos módban. Az egy- és többfiókos móddal, valamint az alkalmazás konfigurálásával kapcsolatos további információkért tekintse meg a dokumentációt

  4. Az app > src mainAndroidManifest.xmladja hozzá az > > **** alábbi BrowserTabActivity tevékenységet az alkalmazás törzséhez. Ez a bejegyzés lehetővé teszi, hogy a Microsoft visszahívja az alkalmazást a hitelesítés befejezése után:

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

    Helyettesítse be a fájlban regisztrált csomagnevet Azure Portal android:host= értéket. Az érték nevére helyettesítse be a Azure Portal kulcs android:path= kivonatát. Az aláírás-kivonat nem lehet URL-kódolású. Győződjön meg arról, hogy az aláírás-kivonat elején egy kezdő / jel áll.

    A "Package Name" (Csomag neve) mezőben a következőre cseréli az android:host értéket: "com.azuresamples.msalandroidapp". A "Signature Hash" (Aláírás-kivonat), amely értékre cseréli az értékét, a következő módon kell android:path kinéznie: "/1wIqXSqBj7w+h11ZifsnqwgyKrY=".

    Ezeket az értékeket az alkalmazásregisztráció Hitelesítés panelje is megtalálja. Vegye figyelembe, hogy az átirányítási URI a következő módon fog kinézni: "msauth://com.azuresamples.msalandroidapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D". Bár az aláírás-kivonat URL-címe ennek az értéknek a végén van kódolva, az aláírás-kivonatot nem szabad az ön értékében android:path kódolni.

Az MSAL használata

MSAL hozzáadása a projekthez

  1. A Android Studio projektablakban lépjen az app > build.gradle lapra, és adja hozzá a következőket:

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

    További információk a Microsoft Graph SDK-val

A szükséges importálások

Adja hozzá a következőt az > src > main > java > com.example(yourapp) > MainActivity.java oldal tetejéhez

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 példányának példánya

Változók inicializálása

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;

onLétrehozás

A osztályon belül tekintse meg a következő onCreate() metódust az MSAL a használatával való MainActivity példányosulatával. 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

Figyelje a gombokat, és hívja meg a metódusokat, vagy ennek megfelelően naplózhatja a hibákat.

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

Fontos

Az MSAL-kijelentkezés eltávolítja a felhasználó összes ismert adatát az alkalmazásból, de a felhasználónak továbbra is aktív munkamenete lesz az eszközén. Ha a felhasználó újra megpróbál bejelentkezni, előfordulhat, hogy a bejelentkezési felhasználói felület adatokat lát, de előfordulhat, hogy nem kell újból megadnia a hitelesítő adatait, mert az eszköz munkamenete még aktív.

getAuthInteractiveCallback

Az interaktív kérelmekhez használt visszahívás.

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

Csendes kérések esetén használt visszahívás

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 meghívása

A következő kód bemutatja, hogyan hívható meg a GraphAPI az Graph SDK-val.

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

Felhasználói felület hozzáadása

Tevékenység

Ha a felhasználói felületet az oktatóanyagból szeretné modellni, az alábbi módszerek útmutatást nyújtanak a szöveg frissítéséhez és a gombok figyeléséhez.

updateUI

Gombok engedélyezése/letiltása a bejelentkezési állapot alapján és szöveg beállítása.

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

Módszer a szöveg frissítésére a felhasználói felületen a kijelentkezésnek megfelelően.

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

Layout

Mintafájl activity_main.xml gombok és szövegmezők megjelenítéséhez.

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

Az alkalmazás tesztelése

Helyi futtatás

Készítse el és telepítse az alkalmazást egy teszteszközön vagy emulátoron. Be kell tudnia jelentkezni, és jogkivonatokat le kell szereznie az Azure AD-hez vagy a személyes Microsoft-fiókokhoz.

Miután bejelentkezik, az alkalmazás megjeleníti a Microsoft által visszaadott adatokat Graph /me végponton. 4. lekért

Amikor egy felhasználó először jelentkezik be az alkalmazásba, a Microsoft identitása kérni fogja, hogy járul hozzá a kért engedélyekhez. Egyes Azure AD-bérlők letiltották a felhasználói jóváhagyást, amely megköveteli a rendszergazdáktól, hogy az összes felhasználó nevében járulnak hozzá. A forgatókönyv támogatásához létre kell hoznia egy saját bérlőt, vagy rendszergazdai jóváhagyást kell kapnia.

Az erőforrások eltávolítása

Ha már nincs rá szükség, törölje az Alkalmazás regisztrálása lépésben létrehozott alkalmazásobjektumot.

Súgó és támogatás

Ha segítségre van szüksége, jelentsen egy problémát, vagy szeretne többet megtudni a támogatási lehetőségekről, lásd: Súgó és támogatás fejlesztőknek.

Következő lépések

A többrészes forgatókönyv-sorozatban további információt olvashat a védett webes API-kat hívó mobilalkalmazások építésről.