Tutorial: Mehrere APIs in einer iOS/macOS App mit nativer Authentifizierung aufrufen

Gilt für:Weißer Kreis mit grauem X-Symbol. Mitarbeitermieter Grüner Kreis mit weißem Häkchen-Symbol. Externe Mieter (weitere Informationen)

In diesem Tutorial lernen Sie, wie Sie ein Zugriffstoken erwerben und eine API in Ihrer iOS/macOS App aufrufen. Mit dem nativen Authentifizierungs-SDK der Microsoft Bibliothek (MSAL) für iOS/macOS können Sie mehrere Zugangstoken mit einer einzigen Anmeldung erwerben. Mit dieser Funktion können Sie einzelne oder mehrere Zugriffstoken abrufen, ohne dass Benutzer:innen erneut authentifiziert werden müssen.

In diesem Tutorial werden Sie:

  • Abrufen eines oder mehrerer Zugriffstoken.
  • Aufrufen einer API

Voraussetzungen

Abrufen eines oder mehrerer Zugriffstoken

Das native MSAL-Authentifizierungs-SDK kann mehrere Zugriffstoken speichern. Nachdem Sie sich angemeldet haben, können Sie ein Zugriffstoken erhalten, indem Sie die Funktion getAccessToken(parameters:) verwenden und die Bereiche für das neue Zugriffstoken angeben, das Sie vergeben möchten.

  1. Verwenden Sie den folgenden Codeschnipsel, um Werte für mehrere API-Gültigkeitsbereiche zu deklarieren und festzulegen:

    let protectedAPIUrl1: String? = nil
    let protectedAPIUrl2: String? = nil 
    let protectedAPIScopes1: [String] = []
    let protectedAPIScopes2: [String] = []
    
    var accessTokenAPI1: String?
    var accessTokenAPI2: String?
    
    • Initialisieren Sie protectedAPIUrl1 mit der URL Ihrer ersten Web-API.
    • Initialisieren Sie protectedAPIUrl2 mit der URL Ihrer zweiten Web-API.
    • Definieren Sie protectedAPIScopes1 mit Bereichen für Ihre erste API, wie ["api://<Resource_App_ID>/ToDoList.Read", "api://<Resource_App_ID>/ToDoList.ReadWrite"].
    • Definieren Sie protectedAPIScopes2 mit Bereichen für Ihre zweite API, ähnlich wie protectedAPIScopes1.
    • Deklarieren Sie die optionalen Zeichenfolgenvariablen accessTokenAPI1 und accessTokenAPI2.
  2. Melden Sie Benutzende mit dem folgenden Codeschnipsel an:

    @IBAction func signInPressed(_: Any) {
        guard let email = emailTextField.text, let password = passwordTextField.text else {
            resultTextView.text = "Email or password not set"
            return
        }
    
        print("Signing in with email \(email) and password")
    
        showResultText("Signing in...")
        let parameters = MSALNativeAuthSignInParameters(username: email)
        parameters.password = password
        nativeAuth.signIn(parameters: parameters, delegate: self)
    }
    

    Die Methode signInPressed behandelt das Drücken der Anmeldetaste. Es wird geprüft, ob die Felder E-Mail und Passwort ausgefüllt sind. Wenn eines der beiden Felder leer ist, wird „E-Mail oder Kennwort nicht festgelegt“ angezeigt. Wenn beide Felder ausgefüllt sind, wird die E-Mail protokolliert, „Anmelden...“ angezeigt und die Anmeldung mit der signIn-Methode von nativeAuth mit der angegebenen E-Mail und dem Passwort eingeleitet. Das SDK ruft ein Token ab, das für die Standardmäßigen OIDC-Bereiche (OpenID, offline_access, Profil) gültig ist, da keine Bereiche angegeben werden.

  3. Rufen Sie mindestens ein Zugriffstoken mithilfe des folgenden Codeschnipsels ab:

    @IBAction func protectedApi1Pressed(_: Any) {
        guard let url = protectedAPIUrl1, !protectedAPIScopes1.isEmpty else {
            showResultText("API 1 not configured.")
            return
        }
    
        if let accessToken = accessTokenAPI1 {
            accessProtectedAPI(apiUrl: url, accessToken: accessToken)
        } else {
            let parameters = MSALNativeAuthGetAccessTokenParameters()
            parameters.scopes = protectedAPIScopes1
            accountResult?.getAccessToken(parameters: parameters, delegate: self)
            let message = "Retrieving access token to use with API 1..."
            showResultText(message)
            print(message)
        }
    }
    
    @IBAction func protectedApi2Pressed(_: Any) {
        guard let url = protectedAPIUrl2, !protectedAPIScopes2.isEmpty else {
            showResultText("API 2 not configured.")
            return
        }
    
        if let accessToken = accessTokenAPI2 {
            accessProtectedAPI(apiUrl: url, accessToken: accessToken)
        } else {
            let parameters = MSALNativeAuthGetAccessTokenParameters()
            parameters.scopes = protectedAPIScopes2
            accountResult?.getAccessToken(parameters: parameters, delegate: self)
            let message = "Retrieving access token to use with API 2..."
            showResultText(message)
            print(message)
        }
    }
    

    Die Methoden protectedApi1Pressed und protectedApi2Pressed verwalten den Prozess des Erwerbs von Zugriffstoken für zwei verschiedene Gruppen von Bereichen. Sie stellen zunächst sicher, dass die URL und Bereiche jeder API ordnungsgemäß konfiguriert sind. Wenn bereits ein Zugriffstoken für die API verfügbar ist, greift es direkt auf die API zu. Andernfalls fordert es ein Zugriffstoken an und informiert den Benutzenden über den laufenden Token-Abrufprozess.

    Um protectedAPIScopes1 und protectedAPIScopes2 ein Zugriffstoken zuzuweisen, verwenden Sie den folgenden Ausschnitt:

    func onAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult) {
        print("Access Token: \(result.accessToken)")
    
        if protectedAPIScopes1.allSatisfy(result.scopes.contains),
           let url = protectedAPIUrl1
        {
            accessTokenAPI1 = result.accessToken
            accessProtectedAPI(apiUrl: url, accessToken: result.accessToken)
        }
    
        if protectedAPIScopes2.allSatisfy(result.scopes.contains(_:)),
           let url = protectedAPIUrl2
        {
            accessTokenAPI2 = result.accessToken
            accessProtectedAPI(apiUrl: url, accessToken: result.accessToken)
        }
    
        showResultText("Signed in." + "\n\n" + "Scopes:\n\(result.scopes)" + "\n\n" + "Access Token:\n\(result.accessToken)")
        updateUI()
    }
    
    func onAccessTokenRetrieveError(error: MSAL.RetrieveAccessTokenError) {
        showResultText("Error retrieving access token: \(error.errorDescription ?? "No error description")")
    }
    

    Die onAccessTokenRetrieveCompleted Methode druckt das Zugriffstoken auf der Konsole. Dann wird geprüft, ob protectedAPIScopes1 im Ergebnisbereich enthalten ist und ob protectedAPIUrl1 verfügbar ist; wenn ja, wird accessTokenAPI1 gesetzt und accessProtectedAPI mit der URL und dem Token aufgerufen. Es führt eine ähnliche Prüfung für protectedAPIScopes2 und protectedAPIUrl2 durch, aktualisiert accessTokenAPI2 und führt den API-Aufruf durch, wenn die Bedingungen erfüllt sind. Schließlich zeigt die Methode eine Meldung mit dem angemeldeten Status, den Bereichen und dem Zugriffstoken an und aktualisiert die Benutzeroberfläche.

    Die onAccessTokenRetrieveError-Methode zeigt eine Fehlermeldung mit der Beschreibung des Zugriffstokenabruffehlers oder einer Standardmeldung an, wenn keine Beschreibung angegeben wird.

Aufrufen einer API

Verwenden Sie die folgenden Codeschnipsel, um eine API aufzurufen:

func accessProtectedAPI(apiUrl: String, accessToken: String) {
    guard let url = URL(string: apiUrl) else {
        let errorMessage = "Invalid API url"
        print(errorMessage)
        DispatchQueue.main.async {
            self.showResultText(errorMessage)
        }
        return
    }
    
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
    
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            print("Error found when accessing API: \(error.localizedDescription)")
            DispatchQueue.main.async {
                self.showResultText(error.localizedDescription)
            }
            return
        }
        
        guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode)
        else {
            DispatchQueue.main.async {
                self.showResultText("Unsuccessful response found when accessing the API")
            }
            return
        }
        
        guard let data = data, let result = try? JSONSerialization.jsonObject(with: data, options: []) else {
            DispatchQueue.main.async {
                self.showResultText("Couldn't deserialize result JSON")
            }
            return
        }
        
        DispatchQueue.main.async {
            self.showResultText("""
                            Accessed API successfully using access token.
                            HTTP response code: \(httpResponse.statusCode)
                            HTTP response body: \(result)
                            """)
        }
    }
    
    task.resume()
}

Die accessProtectedAPI-Methode sendet mithilfe des bereitgestellten Zugriffstokens eine GET-Anforderung an den angegebenen API-Endpunkt. Sie konfiguriert die Anforderung mit dem Token im Autorisierungsheader. Wenn sie eine erfolgreiche Antwort erhält (HTTP-Statuscode 200-299), deserialisiert er die JSON-Daten und aktualisiert die Benutzeroberfläche mit dem HTTP-Statuscode und dem Antwortkörper. Wenn während der Anforderungs- oder Antwortbehandlung ein Fehler auftritt, wird die Fehlermeldung auf der Benutzeroberfläche angezeigt. Diese Methode ermöglicht den Zugriff auf API 1 oder API 2, je nach bereitgestellter URL und Zugriffstoken.