Zelfstudie: Gebruikers aanmelden en Microsoft Graph aanroepen vanuit een iOS- of macOS-app
In deze zelfstudie bouwt u een iOS- of macOS-app die integreert met het Microsoft-identiteitsplatform voor het aanmelden van gebruikers. U krijgt een toegangstoken waarmee u de Microsoft Graph API kunt aanroepen.
Wanneer u de zelfstudie hebt voltooid, accepteert uw toepassing aanmeldingen van persoonlijke Microsoft-accounts (inclusief outlook.com, live.com en andere accounts) en werk- of schoolaccounts van een bedrijf of organisatie die gebruikmaakt van Microsoft Entra ID. Deze zelfstudie is van toepassing op iOS- en macOS-apps. Sommige stappen verschillen tussen de twee platforms.
In deze zelfstudie:
- Een iOS- of macOS-app-project maken in Xcode
- De app registreren in het Microsoft Entra-beheercentrum
- Code toevoegen voor de ondersteuning van het aan- en afmelden van gebruikers
- Code toevoegen om de Microsoft Graph API aan te roepen
- De app testen
Vereisten
Hoe de zelfstudie-app werkt
Met de app in deze zelfstudie kunnen gebruikers zich aanmelden en gegevens ophalen vanuit Microsoft Graph. Deze gegevens worden geopend via een beveiligde API (Microsoft Graph API in dit geval) waarvoor autorisatie is vereist en die wordt beveiligd door het Microsoft Identity Platform.
Specifieke opdrachten:
- Uw app meldt de gebruiker aan via een browser of microsoft Authenticator.
- De eindgebruiker accepteert de machtigingen die uw toepassing heeft aangevraagd.
- Uw app krijgt een toegangstoken voor de Microsoft Graph API.
- Het toegangstoken is opgenomen in de HTTP-aanvraag voor de web-API.
- Verwerk het Microsoft Graph-antwoord.
In dit voorbeeld wordt de MSAL (Microsoft Authentication Library) gebruikt om Authentication te implementeren. In MSAL worden tokens automatisch vernieuwd, eenmalige aanmelding (SSO) geboden tussen andere apps op het apparaat, en de accounts beheerd.
Als u een voltooide versie wilt downloaden van de app die u in deze zelfstudie hebt gemaakt, kunt u beide versies vinden op GitHub:
- Voorbeeld van iOS-code (Github)
- Voorbeeld van macOS-code (GitHub)
Een nieuw project maken
- Open Xcode en selecteer Een nieuw Xcode-project maken.
- Selecteer voor iOS-apps iOS>App met één weergave, en selecteer Volgende.
- Selecteer voor macOS-apps macOS>Cocoa -app ,en selecteer Volgende.
- Geef een projectnaam op.
- Stel de Taal in op Swift, en selecteer Volgende.
- Selecteer een map om daarin de app te maken en selecteer Maken.
Registreer de toepassing
Tip
Stappen in dit artikel kunnen enigszins variëren op basis van de portal waaruit u begint.
- Meld u als toepassingsontwikkelaar aan bij het Microsoft Entra-beheercentrum.
- Als u toegang hebt tot meerdere tenants, gebruikt u het pictogram Instellingen in het bovenste menu om over te schakelen naar de tenant waarin u de toepassing wilt registreren in het menu Mappen en abonnementen.
- Blader naar identiteitstoepassingen>> App-registraties.
- Selecteer Nieuwe registratie.
- Voer een Naam in voor de toepassing. Gebruikers van uw app kunnen de naam zien. U kunt deze later wijzigen.
- Selecteer Accounts in een organisatiedirectory (Elke Microsoft Entra-directory - Multitenant) en persoonlijke Microsoft-accounts (bijvoorbeeld Skype, Xbox) onder Ondersteunde accounttypen.
- Selecteer Registreren.
- Selecteer onder Beheren achtereenvolgens Verificatie>Een platform toevoegen>iOS/macOS.
- Voer de bundel-id van het project in. Als het codevoorbeeld is gedownload, is
com.microsoft.identitysample.MSALiOS
de bundel-id. Als u uw eigen project maakt, selecteert u uw project in Xcode en opent u het tabblad Algemeen . De bundel-id wordt weergegeven in de sectie Identiteit . - Selecteer Configureren en sla de MSAL-configuratie op die wordt weergegeven op de pagina MSAL-configuratie, zodat u deze kunt invoeren wanneer u de app later configureert.
- Selecteer Gereed.
MSAL toevoegen
Kies een van de volgende manieren om de MSAL in uw app te installeren:
CocoaPods
Als u CocoaPods gebruikt, installeert u
MSAL
door eerst een leeg bestand genaamd podfile te maken in dezelfde map als het .xcodeproj-bestand van uw project. Voeg het volgende aan podfile toe:use_frameworks! target '<your-target-here>' do pod 'MSAL' end
Vervang
<your-target-here>
door de naam van uw project.Navigeer in een terminalvenster naar de map die het podfile bevat dat u hebt gemaakt, en voer
pod install
uit om de MSAL-bibliotheek te installeren.Sluit Xcode en open
<your project name>.xcworkspace
om het project opnieuw te laden in Xcode.
Carthage
Als u Carthagegebruikt, installeert u MSAL
door het toe te voegen aan uw Cartfile:
github "AzureAD/microsoft-authentication-library-for-objc" "master"
Voer vanuit een terminalvenster, in dezelfde map als het bijgewerkte Cartfile, de volgende opdracht uit om de afhankelijkheden in uw project bij te werken met Carthage.
iOS:
carthage update --platform iOS
macOS:
carthage update --platform macOS
Handmatig
U kunt ook een Git-submodule gebruiken of de meest recente release bekijken om te gebruiken als framework in uw toepassing.
De app-registratie toevoegen
Vervolgens voegen we uw app-registratie toe aan uw code.
Voeg eerst de volgende importinstructie toe aan het begin van het bestand ViewController.swift en appDelegate.swift of SceneDelegate.swift:
import MSAL
Voeg daarna de volgende code toe aan ViewController.swift vóór viewDidLoad()
:
// 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?
De enige waarde die u wijzigt, is de waarde die is toegewezen aan kClientID
uw toepassings-id. Deze waarde maakt deel uit van de MSAL-configuratiegegevens die u tijdens de stap aan het begin van deze zelfstudie hebt opgeslagen om de toepassing te registreren.
Xcode-projectinstellingen configureren
Voeg een nieuwe sleutelketengroep toe aan uw project Ondertekening en mogelijkheden. De sleutelketengroep moet zijn: com.microsoft.adalcache
in iOS en com.microsoft.identity.universalstorage
in macOS.
Alleen voor iOS: URL-schema's configureren
In deze stap registreert u CFBundleURLSchemes
, zodat de gebruiker na aanmelding kan worden omgeleid naar de app. Met LSApplicationQueriesSchemes
kan uw app bovendien ook gebruikmaken van Microsoft Authenticator.
Open Info.plist in Xcode als een broncodebestand, en voeg het volgende toe in de sectie <dict>
. Vervang [BUNDLE_ID]
door de waarde die u eerder hebt gebruikt. Als u de code hebt gedownload, is de bundel-id com.microsoft.identitysample.MSALiOS
. Als u uw eigen project maakt, selecteert u uw project in Xcode en opent u het tabblad Algemeen . De bundel-id wordt weergegeven in de sectie Identiteit .
<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>
Alleen voor macOS: App-sandbox configureren
- Ga naar de instellingen voor uw Xcode-project >tabblad Mogelijkheden>App-sandbox
- Selecteer het selectie vakje Uitgaande verbindingen (client).
De gebruikersinterface van uw app maken
Maak nu een gebruikersinterface die een knop voor het aanroepen van de Microsoft Graph API, een knop voor afmelden, en een tekstweergave voor uitvoer bevat, door de volgende code toe te voegen aan de klasse ViewController
:
iOS-gebruikersinterface
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-gebruikersinterface
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() {}
Vervang vervolgens in de klasse ViewController
de methode viewDidLoad()
door:
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()
}
MSAL gebruiken
MSAL initialiseren
Voeg aan de klasse ViewController
de methode initMSAL
toe:
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()
}
Voeg in de klasse ViewController
en na de methode initMSAL
de methode initWebViewParams
toe:
iOS-code:
func initWebViewParams() {
self.webViewParameters = MSALWebviewParameters(authPresentationViewController: self)
}
macOS-code:
func initWebViewParams() {
self.webViewParameters = MSALWebviewParameters()
}
De callback na aanmelding verwerken (alleen voor iOS)
Open het bestand AppDelegate.swift. Als u de callback na aanmelding wilt afhandelen, voegt u MSALPublicClientApplication.handleMSALResponse
toe aan de klasse appDelegate
, zoals:
// 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)
}
Als u Xcode 11 gebruikt, moet u MSAL-callback in plaats hiervan in SceneDelegate.swift plaatsen. Als u ondersteuning biedt voor UISceneDelegate en UIApplicationDelegate voor compatibiliteit met oudere iOS-versies, moet MSAL-callback in beide bestanden worden geplaatst.
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)
}
Tokens verkrijgen
Nu kunnen we verwerkingslogica voor de gebruikersinterface van de toepassing implementeren en interactief tokens ophalen via MSAL.
MSAL biedt twee primaire methoden voor het ophalen van tokens: acquireTokenSilently()
en acquireTokenInteractively()
.
Met
acquireTokenSilently()
wordt geprobeerd om een gebruiker aan te melden en tokens op te halen zonder enige gebruikersinteractie, mits een account aanwezig is.acquireTokenSilently()
vereist een geldigeMSALAccount
, die kan worden opgehaald met behulp van een van de opsommings-API's van MSAL. In deze zelfstudie wordtapplicationContext.getCurrentAccount(with: msalParameters, completionBlock: {})
gebruikt om het huidige account op te halen.Met
acquireTokenInteractively()
wordt altijd de gebruikersinterface weergegeven bij een poging om de gebruiker aan te melden. Voor een interactieve ervaring met eenmalige aanmelding kunnen sessiecookies in de browser worden gebruikt of een account in Microsoft Authenticator.
Voeg de volgende code toe aan de klasse ViewController
:
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)
}
})
}
Interactief een token ophalen
Met het volgende codefragment wordt de eerste keer een token opgehaald door een object MSALInteractiveTokenParameters
te maken en acquireToken
aan te roepen. Vervolgens voegt u code toe die:
MSALInteractiveTokenParameters
maken met bereiken.acquireToken()
aanroepen met de gemaakte parameters.- Fouten afhandelen. Raadpleeg Handleiding voor foutafhandeling in MSAL voor iOS en macOS voor meer details.
- De geslaagde aanvraag afhandelen.
Voeg de volgende code toe aan de klasse ViewController
.
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()
}
}
Met de eigenschap promptType
van MSALInteractiveTokenParameters
configureert u het gedrag voor verificatie en voor de instemmingsprompt. De volgende waarden worden ondersteund:
.promptIfNecessary
(standaard): de gebruiker krijgt alleen een prompt te zien als dat nodig is. De SSO-ervaring wordt bepaald door de aanwezigheid van cookies in de webweergave en door het accounttype. Als er meerdere gebruikers zijn aangemeld, wordt de accountselectie weergegeven. Dit is het standaardgedrag..selectAccount
: als er geen gebruiker is opgegeven, wordt in de webweergave voor verificatie een lijst weergegeven met de op dat moment aangemelde accounts waaruit de gebruiker een selectie kan maken..login
: vereist dat de gebruiker zich verifieert in de webweergave. Er kan slechts één account tegelijk zijn aangemeld als u deze waarde opgeeft..consent
: de gebruiker moet toestemming geven voor de huidige set scopes voor de aanvraag.
Een token op de achtergrond ophalen
Als u een bijgewerkt token op de achtergrond wilt ophalen, voegt u de volgende code toe aan de klasse ViewController
. Hiermee maakt u een object MSALSilentTokenParameters
en roept u acquireTokenSilent()
aan:
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()
}
}
De Microsoft Graph API aanroepen
Zodra u een token hebt, kan de app deze gebruiken in de HTTP-koptekst om een geautoriseerde aanvraag te doen bij Microsoft Graph:
sleutel voor koptekst | waarde |
---|---|
Autorisatie | Bearer-<toegangstoken> |
Voeg de volgende code toe aan de klasse ViewController
:
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()
}
Zie Microsoft Graph API voor meer informatie over de Microsoft Graph API.
MSAL gebruiken voor afmelden
Voeg vervolgens ondersteuning voor afmelden toe.
Belangrijk
Bij afmelden met MSAL wordt alle bekende informatie over een gebruiker verwijderd uit de toepassing. Ook wordt een actieve sessie verwijderd op het apparaat van de gebruiker wanneer dit is toegestaan op basis van de apparaatconfiguratie. U kunt de gebruiker ook afmelden vanuit de browser.
Als u de mogelijkheid voor afmelden wilt toevoegen, voegt u de volgende code toe binnen de klasse ViewController
.
@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)
})
}
}
Tokencaching inschakelen
De tokens van uw app worden met MSAL standaard in de cache opgeslagen in de sleutelketen in iOS of macOS.
Tokencaching inschakelen:
- Zorg ervoor dat de toepassing juist is afgemeld
- Ga naar de instellingen voor uw Xcode-project >tabblad Mogelijkheden>Sleutelketens delen inschakelen
- Selecteer + en voer een van de volgende sleutelhangergroepen in:
- iOS:
com.microsoft.adalcache
- macOS:
com.microsoft.identity.universalstorage
- iOS:
Help-methoden toevoegen
Voeg de volgende Help-methode toe aan de klasse ViewController
om het voorbeeld te voltooien.
iOS-gebruikersinterface:
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-gebruikersinterface:
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)
}
Alleen voor iOS: aanvullende informatie over het apparaat ophalen
Gebruik de volgende code om de huidige apparaatconfiguratie te lezen, inclusief of het apparaat is geconfigureerd als gedeeld:
@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.")
}
}
Toepassingen met meerdere accounts
Deze app is gebouwd voor een enkel accountscenario. MSAL biedt ook ondersteuning voor scenario's met meerdere accounts, maar hiervoor is extra werk voor apps vereist. U moet een gebruikersinterface maken om gebruikers te helpen bij het selecteren van het account dat ze willen gebruiken voor elke actie waarvoor tokens zijn vereist. Uw app kan ook een heuristiek implementeren om te selecteren welk account moet worden gebruikt, door alle account van MSAL te doorzoeken. Zie bijvoorbeeld accountsFromDeviceForParameters:completionBlock:
API
Uw app testen
Bouw en implementeer de app op een testapparaat of simulator. U moet zich kunnen aanmelden en tokens ophalen voor Microsoft Entra ID of persoonlijke Microsoft-accounts.
De eerste keer dat een gebruiker zich aanmeldt bij uw app, wordt diegene door Microsoft gevraagd toestemming te geven voor de aangevraagde machtigingen. Hoewel de meeste gebruikers toestemming kunnen geven, hebben sommige Microsoft Entra-tenants gebruikerstoestemming uitgeschakeld. Hiervoor moeten beheerders toestemming geven namens alle gebruikers. Registreer de bereiken van uw app om dit scenario te ondersteunen.
Nadat u zich hebt aangemeld, verschijnen in de app de gegevens die zijn geretourneerd via het Microsoft Graph /me
-eindpunt.
Volgende stappen
Meer informatie over het bouwen van mobiele apps die beveiligde web-API's aanroepen in deze reeks met meerdere scenario's.