Anmerkung
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Gilt für:
Mitarbeitermandanten
Externe Mandanten (weitere Informationen)
Dies ist das dritte Tutorial in der Tutorialreihe, die Sie durch das Anmelden von Benutzern mit Microsoft Entra ID führt.
Bevor Sie beginnen, verwenden Sie den Selektor Mandantentyp auswählen oben auf dieser Seite, um den Mandantentyp auszuwählen. Die Microsoft Entra-ID stellt zwei Mandantenkonfigurationen, Mitarbeiter und externe Konfigurationen bereit. Eine konfiguration für einen Mitarbeitermandanten richtet sich an Ihre Mitarbeiter, interne Apps und andere Organisationsressourcen. Ein externer Mandant richtet sich an Ihre kundenorientierten Apps.
In diesem Tutorial erfahren Sie:
- Melden Sie sich als Benutzer an.
- Melden Sie den Benutzer ab.
- Erstellen der Benutzeroberfläche Ihrer App
Voraussetzungen
Anmelden von Benutzenden
Für die Anmeldung von Benutzern mit der Microsoft-Authentifizierungsbibliothek (Microsoft Authentication Library, MSAL) für iOS stehen zwei Hauptoptionen zur Verfügung: interaktives oder automatisches Abrufen von Token.
Verwenden Sie den folgenden Code, um sich interaktiv anzumelden:
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 vonMSALInteractiveTokenParameterswerden 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.
-
Verwenden Sie den folgenden Code, um sich stumm anzumelden:
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() } }Die
acquireTokenSilentlyMethode versucht, im Hintergrund ein Zugriffstoken für ein vorhandenes MSAL-Konto abzurufen. Er verwendet dieapplicationContext, um das Token mit den angegebenen Bereichen anzufordern. Wenn ein Fehler auftritt, wird geprüft, ob eine Benutzerinteraktion erforderlich ist, und wenn ja, wird ein interaktiver Token-Erwerb initiiert. Bei erfolgreichem Erfolg wird das Zugriffstoken aktualisiert, das Ergebnis protokolliert, die Schaltfläche zum Abmelden aktiviert und der Inhalt mithilfe des Tokens abgerufen.
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)
}
Abmelden des Benutzers
Von Bedeutung
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)
})
}
}
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()
}
Nächste Schritte
Dies ist das dritte Tutorial in der Tutorialreihe, die Sie durch das Anmelden von Benutzern mit Microsoft Entra ID führt.
Bevor Sie beginnen, verwenden Sie den Selektor Mandantentyp auswählen oben auf dieser Seite, um den Mandantentyp auszuwählen. Die Microsoft Entra-ID stellt zwei Mandantenkonfigurationen, Mitarbeiter und externe Konfigurationen bereit. Eine konfiguration für einen Mitarbeitermandanten richtet sich an Ihre Mitarbeiter, interne Apps und andere Organisationsressourcen. Ein externer Mandant richtet sich an Ihre kundenorientierten Apps.
In diesem Tutorial erfahren Sie:
- Melden Sie sich als Benutzer an.
- Melden Sie den Benutzer ab.
Voraussetzungen
Anmelden von Benutzenden
Für die Anmeldung von Benutzern mit der Microsoft-Authentifizierungsbibliothek (Microsoft Authentication Library, MSAL) für iOS stehen zwei Hauptoptionen zur Verfügung: interaktives oder automatisches Abrufen von Token.
Verwenden Sie den folgenden Code, um sich interaktiv anzumelden:
acquireTokenInteractively() { guard let applicationContext = self.applicationContext else { return } guard let webViewParameters = self.webViewParameters else { return } updateLogging(text: "Acquiring token interactively...") let parameters = MSALInteractiveTokenParameters(scopes: Configuration.kScopes, webviewParameters: webViewParameters) parameters.promptType = .selectAccount applicationContext.acquireToken(with: parameters) { (result, error) in 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 } self.accessToken = result.accessToken self.updateLogging(text: "Access token is \(self.accessToken)") self.updateCurrentAccount(account: result.account) } }Der Code überprüft zunächst, ob der Anwendungskontext und die Webansichtsparameter verfügbar sind. Anschließend wird die Protokollierung aktualisiert, um anzugeben, dass das Token interaktiv abgerufen wird. Als Nächstes werden Parameter für den interaktiven Tokenerwerb eingerichtet, indem die Bereiche und Webansichtsparameter angegeben werden. Außerdem wird der Eingabeaufforderungstyp für die Auswahl eines Kontos festgelegt.
Anschließend ruft es die
acquireTokenMethode im Anwendungskontext mit den definierten Parametern auf. Im Abschlusshandler wird nach Fehlern gesucht. Wenn ein Fehler auftritt, wird die Protokollierung mit der Fehlermeldung aktualisiert. Bei Erfolg ruft es das Zugriffstoken aus dem Ergebnis ab, aktualisiert die Protokollierung mit dem Token und aktualisiert das aktuelle Konto.Sobald Ihre App ein Zugriffstoken abgerufen hat, können Sie die Ansprüche abrufen, die dem aktuellen Konto zugeordnet sind. Verwenden Sie dazu den folgenden Codeschnipsel:
let claims = result.account.accountClaims let preferredUsername = claims?["preferred_username"] as? StringDer Code liest Ansprüche aus dem Konto, indem er auf die
accountClaimsEigenschaft desresult.accountObjekts zugreift. Anschließend wird der Wert des Anspruchs "preferred_username" aus dem Anspruchswörterbuch abgerufen und derpreferredUsernameVariablen zugewiesen.Verwenden Sie den folgenden Code, um sich stumm anzumelden:
func acquireTokenSilently() { self.loadCurrentAccount { (account) in guard let currentAccount = account else { self.updateLogging(text: "No token found, try to acquire a token interactively first") return } self.acquireTokenSilently(currentAccount) } }Der Code initiiert den Prozess des automatischen Abrufens von Token. Zuerst wird versucht, das Girokonto zu laden. Wenn ein Girokonto gefunden wird, wird das Token im Hintergrund über dieses Konto erworben. Wenn kein aktuelles Konto gefunden wird, wird die Protokollierung aktualisiert, um anzuzeigen, dass kein Token gefunden wurde, und es wird vorgeschlagen, zuerst zu versuchen, ein Token interaktiv abzurufen.
Im obigen Code rufen wir zwei Funktionen und
loadCurrentAccountauf.acquireTokenSilentlyDieloadCurrentAccountFunktion sollte den folgenden Code aufweisen:func loadCurrentAccount(completion: AccountCompletion? = nil) { guard let applicationContext = self.applicationContext else { return } let msalParameters = MSALParameters() msalParameters.completionBlockQueue = DispatchQueue.main // Note that this sample showcases an app that signs in a single account at a time 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.updateCurrentAccount(account: currentAccount) self.acquireTokenSilently(currentAccount) if let completion = completion { completion(self.currentAccount) } return } // If testing with Microsoft's shared device mode, see the account that has been signed out from another app. More details here: // https://docs.microsoft.com/azure/active-directory/develop/msal-ios-shared-devices if let previousAccount = previousAccount { self.updateLogging(text: "The account with username \(String(describing: previousAccount.username)) has been signed out.") } else { self.updateLogging(text: "") } self.accessToken = "" self.updateCurrentAccount(account: nil) if let completion = completion { completion(nil) } }) }Der Code verwendet MSAL für iOS, um das aktuelle Konto zu laden. Es wird nach Fehlern gesucht und die Protokollierung entsprechend aktualisiert. Wenn ein aktuelles Konto gefunden wird, wird es aktualisiert und versucht, Token im Hintergrund abzurufen. Wenn ein früheres Konto vorhanden ist, wird die Abmeldung protokolliert. Wenn keine Konten gefunden werden, wird das Zugriffstoken gelöscht. Schließlich führt es einen Abschlussblock aus, falls angegeben.
Die
acquireTokenSilentlyFunktion sollte den folgenden Code enthalten: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. */ updateLogging(text: "Acquiring token silently...") let parameters = MSALSilentTokenParameters(scopes: Configuration.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) } }Diese Funktion verwendet MSAL für iOS, um im Hintergrund ein Token für ein vorhandenes Konto abzurufen. Nach der Überprüfung von
applicationContextwird der Tokenerwerbsprozess protokolliert. MitMSALSilentTokenParametersdefiniert es die notwendigen Parameter. Dann versucht er, das Token im Hintergrund abzurufen. Wenn Fehler auftreten, prüft es die Anforderungen an die Benutzerinteraktion und initiiert bei Bedarf einen interaktiven Prozess. Nach erfolgreichem Erfolg wird dieaccessTokenEigenschaft aktualisiert, das aktualisierte Token protokolliert, wobei die Schaltfläche "Abmelden" aktiviert wird.
Abmelden des Benutzers
Verwenden Sie den folgenden Code, um einen Benutzer über Ihre iOS-App (Swift) mit MSAL für iOS abzumelden:
@IBAction func signOut(_ sender: UIButton) {
guard let applicationContext = self.applicationContext else { return }
guard let account = self.currentAccount else { return }
guard let webViewParameters = self.webViewParameters else { return }
updateLogging(text: "Signing out...")
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: webViewParameters)
// If testing with Microsoft's shared device mode, trigger signout from browser. More details here:
// https://docs.microsoft.com/azure/active-directory/develop/msal-ios-shared-devices
if (self.currentDeviceMode == .shared) {
signoutParameters.signoutFromBrowser = true
} else {
signoutParameters.signoutFromBrowser = false
}
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)
})
}
}
Der Code überprüft das Vorhandensein von applicationContext, currentAccountund webViewParameters. Anschließend wird der Abmeldevorgang protokolliert. Der Code entfernt alle Token aus dem Cache für das angegebene Konto. Abhängig vom aktuellen Gerätemodus wird festgelegt, ob sich der Browser abmeldet. Nach Abschluss wird der Protokollierungstext entsprechend aktualisiert. Wenn während des Abmeldevorgangs ein Fehler auftritt, wird die Fehlermeldung protokolliert. Nach erfolgreicher Abmeldung wird das Zugriffstoken auf eine leere Zeichenfolge aktualisiert und das aktuelle Konto gelöscht.