Tutorial: Anmelden von Benutzern und Aufrufen von Microsoft Graph aus einer iOS- oder macOS-App
In diesem Tutorial erstellen Sie eine iOS- oder macOS-App, die in die Microsoft Identity Platform eingebunden wird, um Benutzer anzumelden und ein Zugriffstoken abzurufen, mit dem die Microsoft Graph-API aufgerufen werden kann.
Am Ende dieses Tutorials wird Ihre Anwendung Anmeldungen von persönlichen Microsoft-Konten (einschließlich outlook.com, live.com und anderen) sowie von Geschäfts-, Schul- oder Unikonten von allen Unternehmen oder Organisationen akzeptieren, die Microsoft Entra ID nutzen. Dieses Tutorial gilt für iOS- und macOS-Apps. Bei diesen beiden Plattformen sind einige Schritte unterschiedlich.
Dieses Tutorial umfasst folgende Punkte:
- Erstellen eines iOS- oder macOS-App-Projekts in Xcode
- Registrieren der App im Microsoft Entra Admin Center
- Hinzufügen von Code zur Unterstützung der Benutzeranmeldung und -abmeldung
- Hinzufügen von Code zum Aufrufen der Microsoft Graph-API
- Testen der App
Voraussetzungen
Funktionsweise der Tutorial-App
Mit der App in diesem Tutorial können Benutzer angemeldet und Daten aus Microsoft Graph in deren Namen abgerufen werden. Auf diese Daten wird über eine geschützte API (hier: Microsoft Graph-API) zugegriffen, für die eine Autorisierung erforderlich ist und die über Microsoft Identity Platform geschützt ist.
Dies gilt insbesondere in folgenden Fällen:
- Die App meldet den Benutzer entweder über einen Browser oder über Microsoft Authenticator an.
- Der Endbenutzer akzeptiert die von Ihrer Anwendung angeforderten Berechtigungen.
- Ihre App stellt ein Zugriffstoken für die Microsoft Graph-API aus.
- Das Zugriffstoken ist in der HTTP-Anforderung an die Web-API enthalten.
- Die Microsoft Graph-Antwort wird verarbeitet.
In diesem Beispiel wird die Microsoft-Authentifizierungsbibliothek (Microsoft Authentication Library, MSAL) zum Implementieren der Authentifizierung verwendet. MSAL erneuert Token automatisch, ermöglicht das einmalige Anmelden zwischen anderen Apps auf dem Gerät und verwaltet die Konten.
Wenn Sie eine vollständige Version der App herunterladen möchten, die Sie in diesem Tutorial erstellen, finden Sie beide Versionen auf GitHub:
- iOS-Codebeispiel (GitHub)
- macOS-Codebeispiel (GitHub)
Erstellen eines neuen Projekts
- Starten Sie Xcode, und wählen Sie Create a new Xcode project (Neues Xcode-Projekt erstellen) aus.
- Für iOS-Apps: Wählen Sie iOS>Single view App (Einzelansicht-App) und dann Next (Weiter) aus.
- Für macOS-Aps: Wählen Sie macOS>Cocoa-App und anschließend Next (Weiter) aus.
- Geben Sie einen Produktnamen ein.
- Legen Sie die Sprache auf Swift fest, und wählen Sie Next (Weiter) aus.
- Wählen Sie einen Ordner für das Erstellen Ihrer App und dann die Option Erstellen aus.
Registrieren der Anwendung
Tipp
Die Schritte in diesem Artikel können je nach dem Portal, mit dem Sie beginnen, geringfügig variieren.
- Melden Sie sich beim Microsoft Entra Admin Center mindestens mit der Rolle Anwendungsentwickler an.
- Wenn Sie Zugriff auf mehrere Mandanten haben, verwenden Sie das Symbol für Einstellungen im oberen Menü, um zum Mandanten zu wechseln, in dem Sie die Anwendung über das Menü Verzeichnisse + Abonnements registrieren möchten.
- Browsen Sie zu Identität>Anwendungen>App-Registrierungen.
- Wählen Sie Neue Registrierung aus.
- Geben Sie einen Namen für Ihre Anwendung ein. Benutzern Ihrer App wird wahrscheinlich dieser Namen angezeigt. Sie können ihn später ändern.
- Wählen Sie unter Unterstützte Kontotypen die Option Konten in allen Microsoft Entra-Verzeichnissen (beliebiges Microsoft Entra-Verzeichnis: mehrere Mandanten) und persönliche Microsoft-Konten (z. B. Skype, Xbox) aus.
- Wählen Sie Registrieren aus.
- Wählen Sie unter Verwalten die Optionen Authentifizierung>Plattform hinzufügen>iOS/macOS aus.
- Geben Sie die Bündel-ID Ihres Projekts ein. Wenn das Codebeispiel heruntergeladen wurde, lautet die Bundle-ID
com.microsoft.identitysample.MSALiOS
. Wählen Sie bei der Erstellung eines eigenen Projekts Ihr Projekt in Xcode aus, und öffnen Sie die Registerkarte General (Allgemein). Die Paket-ID wird im Abschnitt Identity (Identität) angezeigt. - Wählen Sie Konfigurieren aus, und speichern Sie die MSAL-Konfiguration, die auf der Seite MSAL-Konfiguration angezeigt wird, damit Sie diese später beim Konfigurieren Ihrer App eingeben können.
- Wählen Sie Fertigaus.
Hinzufügen von MSAL
Installieren Sie MSAL mit einer der folgenden Optionen in Ihrer App:
CocoaPods
Wenn Sie CocoaPods verwenden, installieren Sie
MSAL
. Erstellen Sie dazu zunächst in dem Ordner, in dem sich auch die Datei .xcodeproj Ihres Projekts befindet, eine leere Datei namens podfile. Fügen Sie der Datei podfile Folgendes hinzu:use_frameworks! target '<your-target-here>' do pod 'MSAL' end
Ersetzen Sie
<your-target-here>
durch den Namen Ihres Projekts.Navigieren Sie in einem Terminalfenster zu dem Ordner, der die erstellte Datei podfile enthält, und führen Sie
pod install
zum Installieren der MSAL-Bibliothek aus.Schließen Sie Xcode, und öffnen Sie
<your project name>.xcworkspace
, um das Projekt erneut in Xcode zu laden.
Carthage
Wenn Sie Carthage verwenden, installieren Sie MSAL
, indem Sie die Bibliothek Ihrer Cartfile-Datei hinzufügen:
github "AzureAD/microsoft-authentication-library-for-objc" "master"
Führen Sie in dem Verzeichnis, in dem sich auch die aktualisierte Cartfile-Datei befindet, in einem Terminalfenster den folgenden Befehl aus, damit Carthage die Abhängigkeiten in Ihrem Projekt aktualisiert.
iOS:
carthage update --platform iOS
macOS:
carthage update --platform macOS
Manuell
Sie können auch ein Git-Submodul oder das neueste Release als Framework in Ihrer Anwendung verwenden.
Datum der App-Registrierung
Im nächsten Schritt fügen Sie dem Code die App-Registrierung hinzu.
Fügen Sie zuerst oben in der Datei ViewController.swift die folgende Importanweisung und entweder AppDelegate.swift oder SceneDelegate.swift hinzu:
import MSAL
Fügen Sie als Nächstes den folgenden Code zu ViewController.swift vor viewDidLoad()
hinzu:
// Update the below to your client ID. The below is for running the demo only
let kClientID = "Your_Application_Id_Here"
let kGraphEndpoint = "https://graph.microsoft.com/" // the Microsoft Graph endpoint
let kAuthority = "https://login.microsoftonline.com/common" // this authority allows a personal Microsoft account and a work or school account in any organization's Azure AD tenant to sign in
let kScopes: [String] = ["user.read"] // request permission to read the profile of the signed-in user
var accessToken = String()
var applicationContext : MSALPublicClientApplication?
var webViewParameters : MSALWebviewParameters?
var currentAccount: MSALAccount?
Sie ändern nur den Wert, der kClientID
als Anwendungs-ID zugewiesen wird. Dieser Wert ist Teil der MSAL-Konfigurationsdaten, die Sie am Anfang dieses Tutorials zum Registrieren der Anwendung gespeichert haben.
Konfigurieren von Xcode-Projekteinstellungen
Fügen Sie der Signierung und Funktionen Ihres Projekts eine neue Keychaingruppe hinzu. Die Keychaingruppe sollte unter iOS com.microsoft.adalcache
und unter macOS com.microsoft.identity.universalstorage
lauten.
Nur iOS: Konfigurieren von URL-Schemas
In diesem Schritt registrieren Sie CFBundleURLSchemes
, damit der Benutzer nach der Anmeldung zurück zur App geleitet werden kann. LSApplicationQueriesSchemes
ermöglicht Ihrer App darüber hinaus die Verwendung von Microsoft Authenticator.
Öffnen Sie in Xcode Info.plist als Quellcodedatei, und fügen Sie im Abschnitt <dict>
Folgendes hinzu. Ersetzen Sie [BUNDLE_ID]
durch den Wert, den Sie zuvor verwendet haben. Wenn Sie den Code heruntergeladen haben, lautet die Bundle-ID com.microsoft.identitysample.MSALiOS
. Wählen Sie bei der Erstellung eines eigenen Projekts Ihr Projekt in Xcode aus, und öffnen Sie die Registerkarte General (Allgemein). Die Paket-ID wird im Abschnitt Identity (Identität) angezeigt.
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>msauth.[BUNDLE_ID]</string>
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>msauthv2</string>
<string>msauthv3</string>
</array>
Nur macOS: Konfigurieren der App-Sandbox
- Navigieren Sie zu „Xcode Projekteinstellungen“ >Registerkarte „Funktionen“>App-Sandbox.
- Aktivieren Sie das Kontrollkästchen Outgoing Connections (Client) (Ausgehende Verbindungen (Clients)).
Erstellen der Benutzeroberfläche Ihrer App
Erstellen Sie nun eine Benutzeroberfläche mit einer Schaltfläche zum Aufrufen der Microsoft Graph-API, einer Schaltfläche zum Abmelden und einer Textansicht zum Anzeigen von Ausgaben. Fügen Sie dazu der Klasse ViewController
den folgenden Code hinzu:
iOS-Benutzeroberfläche
var loggingText: UITextView!
var signOutButton: UIButton!
var callGraphButton: UIButton!
var usernameLabel: UILabel!
func initUI() {
usernameLabel = UILabel()
usernameLabel.translatesAutoresizingMaskIntoConstraints = false
usernameLabel.text = ""
usernameLabel.textColor = .darkGray
usernameLabel.textAlignment = .right
self.view.addSubview(usernameLabel)
usernameLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0).isActive = true
usernameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10.0).isActive = true
usernameLabel.widthAnchor.constraint(equalToConstant: 300.0).isActive = true
usernameLabel.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
// Add call Graph button
callGraphButton = UIButton()
callGraphButton.translatesAutoresizingMaskIntoConstraints = false
callGraphButton.setTitle("Call Microsoft Graph API", for: .normal)
callGraphButton.setTitleColor(.blue, for: .normal)
callGraphButton.addTarget(self, action: #selector(callGraphAPI(_:)), for: .touchUpInside)
self.view.addSubview(callGraphButton)
callGraphButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
callGraphButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 120.0).isActive = true
callGraphButton.widthAnchor.constraint(equalToConstant: 300.0).isActive = true
callGraphButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
// Add sign out button
signOutButton = UIButton()
signOutButton.translatesAutoresizingMaskIntoConstraints = false
signOutButton.setTitle("Sign Out", for: .normal)
signOutButton.setTitleColor(.blue, for: .normal)
signOutButton.setTitleColor(.gray, for: .disabled)
signOutButton.addTarget(self, action: #selector(signOut(_:)), for: .touchUpInside)
self.view.addSubview(signOutButton)
signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
signOutButton.topAnchor.constraint(equalTo: callGraphButton.bottomAnchor, constant: 10.0).isActive = true
signOutButton.widthAnchor.constraint(equalToConstant: 150.0).isActive = true
signOutButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
let deviceModeButton = UIButton()
deviceModeButton.translatesAutoresizingMaskIntoConstraints = false
deviceModeButton.setTitle("Get device info", for: .normal);
deviceModeButton.setTitleColor(.blue, for: .normal);
deviceModeButton.addTarget(self, action: #selector(getDeviceMode(_:)), for: .touchUpInside)
self.view.addSubview(deviceModeButton)
deviceModeButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
deviceModeButton.topAnchor.constraint(equalTo: signOutButton.bottomAnchor, constant: 10.0).isActive = true
deviceModeButton.widthAnchor.constraint(equalToConstant: 150.0).isActive = true
deviceModeButton.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
// Add logging textfield
loggingText = UITextView()
loggingText.isUserInteractionEnabled = false
loggingText.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(loggingText)
loggingText.topAnchor.constraint(equalTo: deviceModeButton.bottomAnchor, constant: 10.0).isActive = true
loggingText.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 10.0).isActive = true
loggingText.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -10.0).isActive = true
loggingText.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 10.0).isActive = true
}
func platformViewDidLoadSetup() {
NotificationCenter.default.addObserver(self,
selector: #selector(appCameToForeGround(notification:)),
name: UIApplication.willEnterForegroundNotification,
object: nil)
}
@objc func appCameToForeGround(notification: Notification) {
self.loadCurrentAccount()
}
macOS-Benutzeroberfläche
var callGraphButton: NSButton!
var loggingText: NSTextView!
var signOutButton: NSButton!
var usernameLabel: NSTextField!
func initUI() {
usernameLabel = NSTextField()
usernameLabel.translatesAutoresizingMaskIntoConstraints = false
usernameLabel.stringValue = ""
usernameLabel.isEditable = false
usernameLabel.isBezeled = false
self.view.addSubview(usernameLabel)
usernameLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 30.0).isActive = true
usernameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10.0).isActive = true
// Add call Graph button
callGraphButton = NSButton()
callGraphButton.translatesAutoresizingMaskIntoConstraints = false
callGraphButton.title = "Call Microsoft Graph API"
callGraphButton.target = self
callGraphButton.action = #selector(callGraphAPI(_:))
callGraphButton.bezelStyle = .rounded
self.view.addSubview(callGraphButton)
callGraphButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
callGraphButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 50.0).isActive = true
callGraphButton.heightAnchor.constraint(equalToConstant: 34.0).isActive = true
// Add sign out button
signOutButton = NSButton()
signOutButton.translatesAutoresizingMaskIntoConstraints = false
signOutButton.title = "Sign Out"
signOutButton.target = self
signOutButton.action = #selector(signOut(_:))
signOutButton.bezelStyle = .texturedRounded
self.view.addSubview(signOutButton)
signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
signOutButton.topAnchor.constraint(equalTo: callGraphButton.bottomAnchor, constant: 10.0).isActive = true
signOutButton.heightAnchor.constraint(equalToConstant: 34.0).isActive = true
signOutButton.isEnabled = false
// Add logging textfield
loggingText = NSTextView()
loggingText.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(loggingText)
loggingText.topAnchor.constraint(equalTo: signOutButton.bottomAnchor, constant: 10.0).isActive = true
loggingText.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 10.0).isActive = true
loggingText.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -10.0).isActive = true
loggingText.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -10.0).isActive = true
loggingText.widthAnchor.constraint(equalToConstant: 500.0).isActive = true
loggingText.heightAnchor.constraint(equalToConstant: 300.0).isActive = true
}
func platformViewDidLoadSetup() {}
Ersetzen Sie anschließend ebenfalls innerhalb der Klasse ViewController
die Methode viewDidLoad()
durch Folgendes:
override func viewDidLoad() {
super.viewDidLoad()
initUI()
do {
try self.initMSAL()
} catch let error {
self.updateLogging(text: "Unable to create Application Context \(error)")
}
self.loadCurrentAccount()
self.platformViewDidLoadSetup()
}
Verwendung von MSAL
MSAL initialisieren
Fügen Sie der Klasse ViewController
die Methode initMSAL
hinzu:
func initMSAL() throws {
guard let authorityURL = URL(string: kAuthority) else {
self.updateLogging(text: "Unable to create authority URL")
return
}
let authority = try MSALAADAuthority(url: authorityURL)
let msalConfiguration = MSALPublicClientApplicationConfig(clientId: kClientID, redirectUri: nil, authority: authority)
self.applicationContext = try MSALPublicClientApplication(configuration: msalConfiguration)
self.initWebViewParams()
}
Fügen Sie weiterhin in der Klasse ViewController
und nach der Methode initMSAL
die Methode initWebViewParams
hinzu:
iOS-Code:
func initWebViewParams() {
self.webViewParameters = MSALWebviewParameters(authPresentationViewController: self)
}
macOS-Code:
func initWebViewParams() {
self.webViewParameters = MSALWebviewParameters()
}
Behandeln des Anmelderückrufs (nur iOS)
Öffnen Sie die Datei AppDelegate.swift. Zur Verarbeitung des Rückrufs nach der Anmeldung fügen Sie MSALPublicClientApplication.handleMSALResponse
wie folgt der Klasse appDelegate
hinzu:
// Inside AppDelegate...
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String)
}
Bei Verwendung von Xcode 11 müssen Sie den MSAL-Rückruf stattdessen in der Datei SceneDelegate.swift anordnen. Wenn Sie zur Erzielung von Kompatibilität mit älteren iOS-Versionen sowohl „UISceneDelegate“ als auch „UIApplicationDelegate“ unterstützen, muss der MSAL-Rückruf in beide Dateien eingefügt werden.
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let urlContext = URLContexts.first else {
return
}
let url = urlContext.url
let sourceApp = urlContext.options.sourceApplication
MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: sourceApp)
}
Abrufen von Token
Jetzt können Sie die Verarbeitungslogik der Anwendungsbenutzeroberfläche implementieren und Token interaktiv über MSAL beziehen.
MSAL macht zwei primäre Methoden zum Abrufen von Token verfügbar: acquireTokenSilently()
und acquireTokenInteractively()
.
acquireTokenSilently()
versucht, einen Benutzer anzumelden und Token ohne Benutzerinteraktion abzurufen, solange ein Konto vorhanden ist.acquireTokenSilently()
erfordert die Angabe eines gültigenMSALAccount
, das mit einer der APIs für MSAL-Kontoenumeration abgerufen werden kann. In diesem Tutorial wird das aktuelle Konto mitapplicationContext.getCurrentAccount(with: msalParameters, completionBlock: {})
abgerufen.acquireTokenInteractively()
zeigt stets die Benutzeroberfläche an, wenn versucht wird, den Benutzer anzumelden. Möglicherweise werden jedoch Sitzungscookies im Browser oder ein Konto in Microsoft Authenticator verwendet, um eine interaktive Anmeldung per SSO bereitzustellen.
Fügen Sie der ViewController
-Klasse den folgenden Code hinzu:
func getGraphEndpoint() -> String {
return kGraphEndpoint.hasSuffix("/") ? (kGraphEndpoint + "v1.0/me/") : (kGraphEndpoint + "/v1.0/me/");
}
@objc func callGraphAPI(_ sender: AnyObject) {
self.loadCurrentAccount { (account) in
guard let currentAccount = account else {
// We check to see if we have a current logged in account.
// If we don't, then we need to sign someone in.
self.acquireTokenInteractively()
return
}
self.acquireTokenSilently(currentAccount)
}
}
typealias AccountCompletion = (MSALAccount?) -> Void
func loadCurrentAccount(completion: AccountCompletion? = nil) {
guard let applicationContext = self.applicationContext else { return }
let msalParameters = MSALParameters()
msalParameters.completionBlockQueue = DispatchQueue.main
applicationContext.getCurrentAccount(with: msalParameters, completionBlock: { (currentAccount, previousAccount, error) in
if let error = error {
self.updateLogging(text: "Couldn't query current account with error: \(error)")
return
}
if let currentAccount = currentAccount {
self.updateLogging(text: "Found a signed in account \(String(describing: currentAccount.username)). Updating data for that account...")
self.updateCurrentAccount(account: currentAccount)
if let completion = completion {
completion(self.currentAccount)
}
return
}
self.updateLogging(text: "Account signed out. Updating UX")
self.accessToken = ""
self.updateCurrentAccount(account: nil)
if let completion = completion {
completion(nil)
}
})
}
Interaktives Abrufen eines Tokens
Der folgende Codeausschnitt ruft ein Token zum ersten Mal ab, indem ein MSALInteractiveTokenParameters
-Objekt erstellt und acquireToken
aufgerufen wird. Im nächsten Schritt fügen Sie Code für folgende Aktionen hinzu:
- Erstellen von
MSALInteractiveTokenParameters
mit Bereichen - Aufrufen von
acquireToken()
mit den erstellten Parametern - Behandeln von Fehlern. Weitere Informationen finden Sie im MSAL-Leitfaden zur Fehlerbehandlung für iOS und macOS.
- Verarbeiten der erfolgreichen Situation
Fügen Sie der ViewController
-Klasse den folgenden Code hinzu.
func acquireTokenInteractively() {
guard let applicationContext = self.applicationContext else { return }
guard let webViewParameters = self.webViewParameters else { return }
// #1
let parameters = MSALInteractiveTokenParameters(scopes: kScopes, webviewParameters: webViewParameters)
parameters.promptType = .selectAccount
// #2
applicationContext.acquireToken(with: parameters) { (result, error) in
// #3
if let error = error {
self.updateLogging(text: "Could not acquire token: \(error)")
return
}
guard let result = result else {
self.updateLogging(text: "Could not acquire token: No result returned")
return
}
// #4
self.accessToken = result.accessToken
self.updateLogging(text: "Access token is \(self.accessToken)")
self.updateCurrentAccount(account: result.account)
self.getContentWithToken()
}
}
Mit der promptType
-Eigenschaft von MSALInteractiveTokenParameters
werden die Authentifizierung und das Verhalten der Einwilligungsaufforderung konfiguriert. Die folgenden Werte werden unterstützt:
.promptIfNecessary
(Standardwert): Die Aufforderung wird dem Benutzer nur bei Bedarf angezeigt. Die SSO-Benutzeroberfläche hängt vom Vorhandensein von Cookies in der Webansicht und vom Kontotyp ab. Wenn mehrere Benutzer angemeldet sind, wird die Kontoauswahl angezeigt. Dies ist das Standardverhalten..selectAccount
: Wenn kein Benutzer angegeben ist, wird in der Webansicht für die Authentifizierung eine Liste mit den derzeit angemeldeten Konten angezeigt, zwischen denen der Benutzer wählen kann..login
: Der Benutzer muss sich in der Webansicht authentifizieren. Wenn Sie diesen Wert angeben, kann nur jeweils ein Konto gleichzeitig angemeldet sein..consent
: Der Benutzer muss seine Einwilligung zu den aktuellen Bereichen für die Anforderung erteilen.
Automatisches Abrufen eines Tokens
Fügen Sie der Klasse ViewController
den folgenden Code hinzu, um automatisch ein aktualisiertes Token abzurufen. Ein MSALSilentTokenParameters
-Objekt wird erstellt, und acquireTokenSilent()
wird aufgerufen:
func acquireTokenSilently(_ account : MSALAccount!) {
guard let applicationContext = self.applicationContext else { return }
/**
Acquire a token for an existing account silently
- forScopes: Permissions you want included in the access token received
in the result in the completionBlock. Not all scopes are
guaranteed to be included in the access token returned.
- account: An account object that we retrieved from the application object before that the
authentication flow will be locked down to.
- completionBlock: The completion block that will be called when the authentication
flow completes, or encounters an error.
*/
let parameters = MSALSilentTokenParameters(scopes: kScopes, account: account)
applicationContext.acquireTokenSilent(with: parameters) { (result, error) in
if let error = error {
let nsError = error as NSError
// interactionRequired means we need to ask the user to sign-in. This usually happens
// when the user's Refresh Token is expired or if the user has changed their password
// among other possible reasons.
if (nsError.domain == MSALErrorDomain) {
if (nsError.code == MSALError.interactionRequired.rawValue) {
DispatchQueue.main.async {
self.acquireTokenInteractively()
}
return
}
}
self.updateLogging(text: "Could not acquire token silently: \(error)")
return
}
guard let result = result else {
self.updateLogging(text: "Could not acquire token: No result returned")
return
}
self.accessToken = result.accessToken
self.updateLogging(text: "Refreshed Access token is \(self.accessToken)")
self.updateSignOutButton(enabled: true)
self.getContentWithToken()
}
}
Aufrufen der Microsoft Graph-API
Sobald Sie ein Token erhalten haben, kann Ihre App es im HTTP-Header verwenden, um eine autorisierte Anforderung an Microsoft Graph zu stellen:
Headerschlüssel | value |
---|---|
Authorization | Bearer <acess-token> |
Fügen Sie der ViewController
-Klasse den folgenden Code hinzu:
func getContentWithToken() {
// Specify the Graph API endpoint
let graphURI = getGraphEndpoint()
let url = URL(string: graphURI)
var request = URLRequest(url: url!)
// Set the Authorization header for the request. We use Bearer tokens, so we specify Bearer + the token we got from the result
request.setValue("Bearer \(self.accessToken)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
self.updateLogging(text: "Couldn't get graph result: \(error)")
return
}
guard let result = try? JSONSerialization.jsonObject(with: data!, options: []) else {
self.updateLogging(text: "Couldn't deserialize result JSON")
return
}
self.updateLogging(text: "Result from Graph: \(result))")
}.resume()
}
Weitere Informationen zur Microsoft Graph-API finden Sie hier.
Verwenden von MSAL zur Abmeldung
Als Nächstes fügen Sie Unterstützung für die Abmeldung hinzu.
Wichtig
Die Abmeldung mit MSAL entfernt alle bekannten Informationen über einen Benutzer aus der Anwendung sowie eine aktive Sitzung auf seinem Gerät, wenn dies durch die Gerätekonfiguration zugelassen wird. Optional können Sie den Benutzer auch über den Browser abmelden.
Fügen Sie zum Hinzufügen einer Abmeldefunktion den folgenden Code in die ViewController
-Klasse ein.
@objc func signOut(_ sender: AnyObject) {
guard let applicationContext = self.applicationContext else { return }
guard let account = self.currentAccount else { return }
do {
/**
Removes all tokens from the cache for this application for the provided account
- account: The account to remove from the cache
*/
let signoutParameters = MSALSignoutParameters(webviewParameters: self.webViewParameters!)
signoutParameters.signoutFromBrowser = false // set this to true if you also want to signout from browser or webview
applicationContext.signout(with: account, signoutParameters: signoutParameters, completionBlock: {(success, error) in
if let error = error {
self.updateLogging(text: "Couldn't sign out account with error: \(error)")
return
}
self.updateLogging(text: "Sign out completed successfully")
self.accessToken = ""
self.updateCurrentAccount(account: nil)
})
}
}
Aktivieren der Zwischenspeicherung von Token
MSAL speichert die Token Ihrer App standardmäßig in der iOS- oder macOS-Keychain zwischen.
So aktivieren Sie die Zwischenspeicherung von Token:
- Stellen Sie sicher, dass Ihre Anwendung ordnungsgemäß signiert ist.
- Navigieren Sie zu „Xcode-Projekteinstellungen“ >Registerkarte „Funktionen“>Keychain-Freigabe aktivieren.
- Wählen Sie + aus, und geben Sie eine der folgenden Keychain-Gruppen ein:
- iOS:
com.microsoft.adalcache
- macOS:
com.microsoft.identity.universalstorage
- iOS:
Hinzufügen von Hilfsmethoden
Fügen Sie der Klasse ViewController
die folgenden Hilfsmethoden hinzu, um das Beispiel abzuschließen.
iOS-Benutzeroberfläche:
func updateLogging(text : String) {
if Thread.isMainThread {
self.loggingText.text = text
} else {
DispatchQueue.main.async {
self.loggingText.text = text
}
}
}
func updateSignOutButton(enabled : Bool) {
if Thread.isMainThread {
self.signOutButton.isEnabled = enabled
} else {
DispatchQueue.main.async {
self.signOutButton.isEnabled = enabled
}
}
}
func updateAccountLabel() {
guard let currentAccount = self.currentAccount else {
self.usernameLabel.text = "Signed out"
return
}
self.usernameLabel.text = currentAccount.username
}
func updateCurrentAccount(account: MSALAccount?) {
self.currentAccount = account
self.updateAccountLabel()
self.updateSignOutButton(enabled: account != nil)
}
macOS-Benutzeroberfläche:
func updateLogging(text : String) {
if Thread.isMainThread {
self.loggingText.string = text
} else {
DispatchQueue.main.async {
self.loggingText.string = text
}
}
}
func updateSignOutButton(enabled : Bool) {
if Thread.isMainThread {
self.signOutButton.isEnabled = enabled
} else {
DispatchQueue.main.async {
self.signOutButton.isEnabled = enabled
}
}
}
func updateAccountLabel() {
guard let currentAccount = self.currentAccount else {
self.usernameLabel.stringValue = "Signed out"
return
}
self.usernameLabel.stringValue = currentAccount.username ?? ""
self.usernameLabel.sizeToFit()
}
func updateCurrentAccount(account: MSALAccount?) {
self.currentAccount = account
self.updateAccountLabel()
self.updateSignOutButton(enabled: account != nil)
}
Nur iOS: Abrufen zusätzlicher Geräteinformationen
Verwenden Sie den folgenden Code zum Lesen der aktuellen Gerätekonfiguration, einschließlich Informationen dazu, ob das Gerät als freigegeben konfiguriert ist
@objc func getDeviceMode(_ sender: AnyObject) {
if #available(iOS 13.0, *) {
self.applicationContext?.getDeviceInformation(with: nil, completionBlock: { (deviceInformation, error) in
guard let deviceInfo = deviceInformation else {
self.updateLogging(text: "Device info not returned. Error: \(String(describing: error))")
return
}
let isSharedDevice = deviceInfo.deviceMode == .shared
let modeString = isSharedDevice ? "shared" : "private"
self.updateLogging(text: "Received device info. Device is in the \(modeString) mode.")
})
} else {
self.updateLogging(text: "Running on older iOS. GetDeviceInformation API is unavailable.")
}
}
Anwendungen mit mehreren Konten
Diese App ist für ein Szenario mit einem einzelnen Konto konzipiert. MSAL unterstützt auch Szenarien mit mehreren Konten, was jedoch Mehrarbeit bei der Anwendung erfordert. Sie müssen eine Benutzeroberfläche erstellen, mit der Benutzer das Konto auswählen können, das sie für jede Aktion, die Token erfordert, verwenden möchten. Als Alternative kann Ihre Anwendung eine Heuristik implementieren, um das zu verwendende Konto durch Abfragen aller Konten über MSAL auszuwählen. Siehe beispielsweise die API für accountsFromDeviceForParameters:completionBlock:
Testen Ihrer App
Erstellen Sie die App, und stellen Sie sie auf einem Testgerät oder in einem Simulator bereit. Sie sollten sich anmelden und Token für Microsoft Entra ID oder persönliche Microsoft-Konten abrufen können.
Wenn sich ein Benutzer zum ersten Mal bei Ihrer App anmeldet, wird er von Microsoft aufgefordert, den angeforderten Berechtigungen zuzustimmen. Die meisten Benutzer können zustimmen, allerdings haben einige Microsoft Entra-Mandanten die Zustimmung durch Benutzer deaktiviert, sodass Administratoren im Namen aller Benutzer zustimmen müssen. Zur Unterstützung dieses Szenarios müssen Sie die Bereiche Ihrer App registrieren.
Nach der Anmeldung zeigt die App die vom Microsoft Graph-Endpunkt /me
zurückgegebenen Daten an.
Nächste Schritte
In der mehrteiligen Szenarioreihe erfahren Sie mehr über das Entwickeln von mobilen Apps, die geschützte Web-APIs abrufen.