Oktatóanyag: Felhasználók bejelentkezése és a Microsoft Graph meghívása iOS- vagy macOS-alkalmazásból
Ebben az oktatóanyagban egy olyan iOS- vagy macOS-alkalmazást hoz létre, amely integrálható a Microsoft Identitásplatform a felhasználók aláírásához és egy hozzáférési jogkivonat beszerzéséhez a Microsoft Graph API meghívásához.
Az oktatóanyag elvégzése után az alkalmazás elfogadja a személyes Microsoft-fiókok (beleértve outlook.com, live.com és mások) és a Microsoft Entra-azonosítót használó bármely cég vagy szervezet munkahelyi vagy iskolai fiókjait. Ez az oktatóanyag iOS- és macOS-alkalmazásokra is alkalmazható. Egyes lépések eltérnek a két platformtól.
Ebben az oktatóanyagban:
- iOS- vagy macOS-alkalmazásprojekt létrehozása az Xcode-ban
- Az alkalmazás regisztrálása a Microsoft Entra Felügyeleti központban
- Kód hozzáadása a felhasználói bejelentkezés és kijelentkezés támogatásához
- Kód hozzáadása a Microsoft Graph API meghívásához
- Az alkalmazás tesztelése
Előfeltételek
Az oktatóanyag-alkalmazás működése
Az oktatóanyagban szereplő alkalmazás bejelentkezhet a felhasználókba, és adatokat kérhet le a Microsoft Graphtól a nevükben. Ezek az adatok egy védett API-n (ebben az esetben a Microsoft Graph API-n) keresztül érhetők el, amely engedélyezést igényel, és a Microsoft Identitásplatform védi.
Pontosabban:
- Az alkalmazás egy böngészőn vagy a Microsoft Authenticatoron keresztül jelentkezik be a felhasználóba.
- A végfelhasználó elfogadja az alkalmazás által kért engedélyeket.
- Az alkalmazás hozzáférési jogkivonatot ad ki a Microsoft Graph API-hoz.
- A hozzáférési jogkivonat szerepel a webes API-hoz irányuló HTTP-kérésben.
- Dolgozza fel a Microsoft Graph-választ.
Ez a minta a Microsoft Authentication Library (MSAL) használatával implementálja a hitelesítést. Az MSAL automatikusan megújítja a jogkivonatokat, egyszeri bejelentkezést (SSO) biztosít az eszközön lévő többi alkalmazás között, és kezeli a fiók(ok)t.
Ha az oktatóanyagban elkészített alkalmazás egy kész verzióját szeretné letölteni, mindkét verzió megtalálható a GitHubon:
- iOS-kódminta (GitHub)
- macOS-kódminta (GitHub)
Új projekt létrehozása
- Nyissa meg az Xcode-ot, és válassza az Új Xcode-projekt létrehozása lehetőséget.
- iOS-alkalmazások esetén válassza az iOS>Egynézetes alkalmazás lehetőséget, és válassza a Tovább lehetőséget.
- MacOS-alkalmazások esetén válassza a macOS>Cocoa App lehetőséget, majd a Tovább gombot.
- Adjon meg egy terméknevet.
- Állítsa a Nyelvet Swiftre, és válassza a Tovább gombot.
- Jelöljön ki egy mappát az alkalmazás létrehozásához, és válassza a Létrehozás lehetőséget.
Az alkalmazás regisztrálása
Tipp.
A cikkben szereplő lépések a portáltól függően kissé eltérhetnek.
- Jelentkezzen be a Microsoft Entra felügyeleti központba legalább alkalmazásfejlesztőként.
- Ha több bérlőhöz is hozzáfér, a felső menü Beállítások ikonjával válthat arra a bérlőre, amelyben regisztrálni szeretné az alkalmazást a Könyvtárak + előfizetések menüből.
- Keresse meg az identitásalkalmazásokat>> Alkalmazásregisztrációk.
- Új regisztráció kiválasztása.
- Adja meg az alkalmazás nevét. Előfordulhat, hogy az alkalmazás felhasználói látják ezt a nevet, és később módosíthatja.
- A Támogatott fióktípusok területen válassza ki bármelyik szervezeti könyvtárban (Bármely Microsoft Entra-címtár – Több-bérlős) és személyes Microsoft-fiókokban (pl. Skype, Xbox) lévő fiókokat.
- Válassza ki a pénztárgépet.
- A Kezelés területen válassza a Hitelesítés>hozzáadása platform>hozzáadása iOS/macOS rendszeren lehetőséget.
- Adja meg a projekt csomagazonosítóját. Ha letöltötte a kódmintát, a csomag azonosítója a következő
com.microsoft.identitysample.MSALiOS
: . Ha saját projektet hoz létre, jelölje ki a projektet az Xcode-ban, és nyissa meg az Általános lapot. A csomagazonosító megjelenik az Identitás szakaszban. - Válassza a Konfigurálás lehetőséget, és mentse az MSAL konfigurációs lapon megjelenő MSAL-konfigurációt, hogy később beírhassa azt az alkalmazás konfigurálásakor.
- Válassza a Kész lehetőséget.
MSAL hozzáadása
Az MSAL-kódtár alkalmazásba való telepítésének alábbi módjai közül választhat:
CocoaPods
Ha CocoaPodsot használ, először hozzon
MSAL
létre egy podfile nevű üres fájlt a projekt .xcodeproj fájljával azonos mappában. Adja hozzá a következőket a podfile-hoz:use_frameworks! target '<your-target-here>' do pod 'MSAL' end
Cserélje le
<your-target-here>
a projekt nevére.Egy terminálablakban keresse meg azt a mappát, amely tartalmazza a létrehozott podfájlt , és futtassa
pod install
az MSAL-kódtár telepítéséhez.Zárja be az Xcode-ot, és nyissa meg
<your project name>.xcworkspace
, hogy újra betöltse a projektet az Xcode-ban.
Karthágó
Ha Carthage-t használ, telepítse MSAL
a Cartfile-hoz való hozzáadásával:
github "AzureAD/microsoft-authentication-library-for-objc" "master"
Egy terminálablakban, a frissített Cartfile könyvtárban futtassa a következő parancsot, hogy a Carthage frissítse a projekt függőségeit.
Ios:
carthage update --platform iOS
macOS:
carthage update --platform macOS
Manuálisan
Használhatja a Git Submodule-t is, vagy megtekintheti a legújabb kiadást, amelyet keretrendszerként használhat az alkalmazásban.
Az alkalmazásregisztráció hozzáadása
Ezután hozzáadjuk az alkalmazásregisztrációt a kódhoz.
Először adja hozzá a következő importálási utasítást a ViewController.swift fájl elejéhez, és adja hozzá az AppDelegate.swift vagy a SceneDelegate.swift fájlt:
import MSAL
Ezután adja hozzá a következő kódot a ViewController.swift fájlhoz, mielőtt a következőhöz: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?
Az egyetlen módosítandó érték az az érték, amely az alkalmazásazonosítóhoz van rendelvekClientID
. Ez az érték azon MSAL-konfigurációs adatok része, amelyeket az oktatóanyag elején mentett az alkalmazás regisztrálásához.
Xcode-projektbeállítások konfigurálása
Adjon hozzá egy új kulcskarikacsoportot a projekt aláírási és képességeihez. A kulcskarikacsoportnak iOS-en és com.microsoft.identity.universalstorage
macOS-en kell lenniecom.microsoft.adalcache
.
Csak iOS esetén konfiguráljon URL-sémákat
Ebben a lépésben regisztrálnia CFBundleURLSchemes
kell, hogy a felhasználó visszakerüljön az alkalmazásba a bejelentkezés után. Emellett az LSApplicationQueriesSchemes
alkalmazás a Microsoft Authenticator használatát is lehetővé teszi.
Az Xcode-ban nyissa meg az Info.plist fájlt forráskódfájlként, és adja hozzá a következőt a <dict>
szakaszon belül. Cserélje le [BUNDLE_ID]
a korábban használt értékre. Ha letöltötte a kódot, a csomag azonosítója a következő com.microsoft.identitysample.MSALiOS
: . Ha saját projektet hoz létre, jelölje ki a projektet az Xcode-ban, és nyissa meg az Általános lapot. A csomagazonosító megjelenik az Identitás szakaszban.
<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>
Csak macOS esetén konfigurálja az App Sandboxot
- Nyissa meg az Xcode Project Settings Capabilities (Xcode Project Settings >Capabilities) lap App Sandbox (Alkalmazás tesztkörnyezete) lapját>
- Jelölje be a Kimenő kapcsolatok (Ügyfél) jelölőnégyzetet.
Az alkalmazás felhasználói felületének létrehozása
Most hozzon létre egy felhasználói felületet, amely tartalmaz egy gombot a Microsoft Graph API meghívásához, egy másik kijelentkezéshez, valamint egy szöveges nézetet a kimenet megtekintéséhez, ha hozzáadja az alábbi kódot az ViewController
osztályhoz:
iOS felhasználói felület
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 felhasználói felület
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() {}
Ezután az ViewController
osztályon belül is cserélje le a metódust a viewDidLoad()
következőre:
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 használata
MSAL inicializálása
Adja hozzá a metódust az ViewController
initMSAL
osztályhoz:
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()
}
Még mindig az ViewController
osztályban és a initMSAL
metódus után adja hozzá a metódust initWebViewParams
:
iOS-kód:
func initWebViewParams() {
self.webViewParameters = MSALWebviewParameters(authPresentationViewController: self)
}
macOS-kód:
func initWebViewParams() {
self.webViewParameters = MSALWebviewParameters()
}
A bejelentkezési visszahívás kezelése (csak iOS esetén)
Nyissa meg az AppDelegate.swift fájlt. A bejelentkezés utáni visszahívás kezeléséhez adja hozzá MSALPublicClientApplication.handleMSALResponse
az osztályhoz az appDelegate
alábbi módon:
// 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)
}
Ha Xcode 11-et használ, az MSAL-visszahívást inkább a SceneDelegate.swiftbe kell helyeznie. Ha mind az UISceneDelegate, mind a UIApplicationDelegate támogatja a régebbi iOS-ekkel való kompatibilitást, az MSAL visszahívást mindkét fájlba kell helyezni.
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)
}
Jogkivonatok beszerzése
Most implementálhatjuk az alkalmazás felhasználói felületének feldolgozási logikáját, és interaktívan lekérhetjük a jogkivonatokat az MSAL-on keresztül.
Az MSAL két elsődleges metódust tesz elérhetővé a jogkivonatok lekéréséhez: acquireTokenSilently()
és acquireTokenInteractively()
.
acquireTokenSilently()
megkísérli bejelentkezni egy felhasználót, és felhasználói beavatkozás nélkül lekérni a jogkivonatokat, amíg egy fiók jelen van.acquireTokenSilently()
érvényesMSALAccount
, amely az MSAL-fiók enumerálási API-jainak egyikével kérhető le. Ez az oktatóanyag az aktuális fiók lekérésére használjaapplicationContext.getCurrentAccount(with: msalParameters, completionBlock: {})
.acquireTokenInteractively()
mindig megjelenik a felhasználói felület, amikor megpróbál bejelentkezni a felhasználóba. Használhat munkamenet-cookie-kat a böngészőben vagy a Microsoft hitelesítő fiókjában, hogy interaktív egyszeri bejelentkezést biztosítson.
Adja hozzá a következő kódot az ViewController
osztályhoz:
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)
}
})
}
Jogkivonat interaktív lekérése
Az alábbi kódrészlet először kap jogkivonatot egy MSALInteractiveTokenParameters
objektum létrehozásával és hívásával acquireToken
. Ezután a következő kódot adja hozzá:
- Hatókörökkel hoz létre
MSALInteractiveTokenParameters
. - A létrehozott paraméterekkel rendelkező hívások
acquireToken()
. - Kezeli a hibákat. További részletekért tekintse meg az iOS-hez és a macOS-hez készült MSAL hibakezelési útmutatót.
- Kezeli a sikeres esetet.
Adja hozzá az alábbi kódot a ViewController
osztályhoz.
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()
}
}
A promptType
hitelesítés és a hozzájárulás kérésének viselkedését MSALInteractiveTokenParameters
a tulajdonság konfigurálja. A következő értékek támogatottak:
.promptIfNecessary
(alapértelmezett) – A rendszer csak akkor kéri a felhasználót, ha szükséges. Az egyszeri bejelentkezés élményét a cookie-k webnézetben való jelenléte és a fiók típusa határozza meg. Ha több felhasználó is bejelentkezett, megjelenik a fiókválasztási felület. Ez az alapértelmezett viselkedés..selectAccount
– Ha nincs megadva felhasználó, a hitelesítési webnézet megjeleníti azoknak a jelenleg bejelentkezett fiókoknak a listáját, ahonnan a felhasználó választhat..login
– A felhasználónak hitelesítenie kell magát a webnézetben. Ha megadja ezt az értéket, egyszerre csak egy fiók lehet bejelentkezve..consent
– Megköveteli a felhasználótól, hogy járuljon hozzá a kérés hatóköreinek jelenlegi készletéhez.
Jogkivonat csendes lekérése
Ha csendesen szeretne beszerezni egy frissített jogkivonatot, adja hozzá az alábbi kódot az ViewController
osztályhoz. Létrehoz egy objektumot MSALSilentTokenParameters
, és meghívja a következőt acquireTokenSilent()
:
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()
}
}
A Microsoft Graph API meghívása
Miután rendelkezik egy jogkivonattal, az alkalmazás a HTTP-fejlécben használhatja egy engedélyezett kérést a Microsoft Graphhoz:
fejléckulcs | Érték |
---|---|
Engedélyezés | Tulajdonosi <hozzáférési jogkivonat> |
Adja hozzá a következő kódot az ViewController
osztályhoz:
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()
}
A Microsoft Graph API-val kapcsolatos további információkért tekintse meg a Microsoft Graph API-t .
MSAL használata kijelentkezéshez
Ezután adja hozzá a kijelentkezés támogatását.
Fontos
Az MSAL használatával való kijelentkezés eltávolítja a felhasználó összes ismert információját az alkalmazásból, valamint eltávolít egy aktív munkamenetet az eszközén, ha az eszközkonfiguráció engedélyezi. Igény szerint kijelentkeztetheti a felhasználót a böngészőből.
A bejelentkezési képesség hozzáadásához adja hozzá a következő kódot az ViewController
osztályon belül.
@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)
})
}
}
Jogkivonat gyorsítótárazásának engedélyezése
Alapértelmezés szerint az MSAL gyorsítótárazza az alkalmazás jogkivonatait az iOS- vagy macOS-kulcskarikában.
A tokenek gyorsítótárazásának engedélyezése:
- Győződjön meg arról, hogy az alkalmazás megfelelően van aláírva
- Lépjen az Xcode Project Settings Capabilities (Az Xcode projekt beállításainak >képességei) lapra a Kulcskarika megosztásának engedélyezése lapon>
- Válassza ki + és adja meg az alábbi kulcskarikacsoportok egyikét:
- Ios:
com.microsoft.adalcache
- macOS:
com.microsoft.identity.universalstorage
- Ios:
Segédmetenek hozzáadása
A minta elvégzéséhez adja hozzá az alábbi segédmetórát az ViewController
osztályhoz.
iOS felhasználói felület:
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 felhasználói felület:
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)
}
Csak iOS: további eszközinformációk lekérése
A következő kóddal olvassa be az aktuális eszközkonfigurációt, beleértve azt is, hogy az eszköz megosztottként van-e konfigurálva:
@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.")
}
}
Többfiókos alkalmazások
Ez az alkalmazás egyetlen fiókhoz készült. Az MSAL többfiókos forgatókönyveket is támogat, de több alkalmazásmunkát igényel. Felhasználói felületet kell létrehoznia, hogy a felhasználók kiválaszthatják, melyik fiókot szeretnék használni minden olyan művelethez, amelyhez jogkivonatokra van szükség. Másik lehetőségként az alkalmazás heurisztikus megoldást is alkalmazhat a használni kívánt fiók kiválasztásához az összes fiók MSAL-ből való lekérdezésével. Lásd például az API-t accountsFromDeviceForParameters:completionBlock:
Az alkalmazás tesztelése
Az alkalmazást egy teszteszközön vagy szimulátoron hozhatja létre és helyezheti üzembe. Be kell tudnia jelentkezni, és jogkivonatokat kell beszereznie a Microsoft Entra-azonosítóhoz vagy a személyes Microsoft-fiókokhoz.
Amikor egy felhasználó először jelentkezik be az alkalmazásba, a Microsoft identitása kérni fogja, hogy járuljon hozzá a kért engedélyekhez. Bár a felhasználók többsége képes a hozzájárulásra, egyes Microsoft Entra-bérlők letiltották a felhasználói hozzájárulást, ami megköveteli, hogy a rendszergazdák az összes felhasználó nevében hozzájárulást adjanak. A forgatókönyv támogatásához regisztrálja az alkalmazás hatóköreit.
A bejelentkezés után az alkalmazás megjeleníti a Microsoft Graph-végpontról /me
visszaadott adatokat.
Következő lépések
Többrészes forgatókönyv-sorozatunkban további információ a védett webes API-kat hívó mobilalkalmazások készítéséről.