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
Krav
- Android Studio 3.5+
Så här fungerar den här självstudien
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 får en åtkomsttoken för Microsoft Graph API.
- Åtkomsttoken inkluderas i HTTP-begäran till webb-API:et.
- Bearbeta Microsoft Graph-svaret.
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.
- Öppna Android Studio och välj Starta ett nytt Android Studio-projekt.
- Välj Grundläggande aktivitet och välj Nästa.
- Namnge ditt program.
- Spara paketnamnet. Du kommer att ange den senare i Azure-Portal.
- Ändra språket från Kotlin till Java.
- Ange den lägsta API-nivån till API 19 eller högre och klicka på Slutför.
- I projektvyn väljer du Projekt i listrutan för att visa käll- och icke-källprojektfiler, öppnar app/build.gradle och anger
targetSdkVersion
till28
.
Integrera med Microsoft-autentiseringsbiblioteket
Registrera ditt program
Logga in på Azure-portalen.
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.
Sök efter och välj Azure Active Directory.
Under Hantera väljer du App-registraties>Ny registrering.
Ange ett namn för ditt program. Användare av din app kan se det här namnet och du kan ändra det senare.
Välj Register (Registrera).
Under Hantera väljer du Autentisering>Lägg till en Plattform>Android.
Ange projektets paketnamn. Om du laddade ned koden är
com.azuresamples.msalandroidapp
det här värdet .I avsnittet Signaturhash på sidan Konfigurera din Android-app väljer du Generera en utvecklingssignaturhash. 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-dokumentationen om hur du genererar en nyckel .
Ange den signatur-hash som genererats av KeyTool.
Välj Konfigurera och spara MSAL-konfigurationen som visas på Android-konfigurationssidan så att du kan ange den när du konfigurerar appen senare.
Välj Klar.
Konfigurera ditt program
I Projektfönstret i Android Studio navigerar du till app\src\main\res.
Högerklicka på res och välj Ny>katalog. Ange
raw
som nytt katalognamn och klicka på OK.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
I app>src>main>AndroidManifest.xmllägger du till
BrowserTabActivity
aktiviteten nedan i programtexten. Med den här posten kan Microsoft anropa tillbaka till 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 paketnamnet som du registrerade i Azure-Portal med
android:host=
värdet . Ersätt nyckelhashen som du registrerade i Azure-Portal motandroid: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ärdetandroid: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 dittandroid:path
värde.
Använda MSAL
Lägga till MSAL i projektet
I projektfönstret för Android Studio går du till app>build.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") }
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 data som returneras från Microsoft Graph-slutpunkten/me
.
PR 4
Samtycke
Första gången någon användare loggar in på din app uppmanas de av Microsoft identitet 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
Mer informasjon om att skapa mobilappar som anropar skyddade webb-API:er i vår scenarioserie i flera delar.