Zelfstudie: Meerdere API's aanroepen in de iOS-/macOS-app met behulp van systeemeigen verificatie

Van toepassing op: Groene cirkel met een wit vinkje dat aangeeft dat de volgende inhoud van toepassing is op externe tenants. Externe tenants (meer informatie)

In deze zelfstudie leert u hoe u een toegangstoken verkrijgt en een API aanroept in uw iOS-/macOS-app. Met microsoft Authentication Library (MSAL) native authentication SDK voor iOS/macOS kunt u meerdere toegangstokens verkrijgen met eenmalige aanmelding. Met deze mogelijkheid kunt u een of meer toegangstokens verkrijgen zonder dat een gebruiker zich opnieuw moet verifiëren.

In deze handleiding leert u:

  • Een of meer toegangstokens verkrijgen.
  • Een API aanroepen

Voorwaarden

Een of meer toegangstokens verkrijgen

DE SYSTEEMeigen VERIFICATIE-SDK van MSAL kan meerdere toegangstokens opslaan. Nadat u zich hebt aangemeld, kunt u een toegangstoken verkrijgen met behulp van de functie getAccessToken(parameters:) en de machtigingen voor het nieuwe toegangstoken opgeven die u wilt toekennen.

  1. Declareer en stel waarden in voor een set API-bereiken met behulp van het volgende codefragment:

    let protectedAPIUrl1: String? = nil
    let protectedAPIUrl2: String? = nil 
    let protectedAPIScopes1: [String] = []
    let protectedAPIScopes2: [String] = []
    
    var accessTokenAPI1: String?
    var accessTokenAPI2: String?
    
    • Initialiseer protectedAPIUrl1 met de URL van uw eerste web-API.
    • Initialiseer protectedAPIUrl2 met de URL van uw tweede web-API.
    • Definieer protectedAPIScopes1 met scope voor uw eerste API, zoals ["api://<Resource_App_ID>/ToDoList.Read", "api://<Resource_App_ID>/ToDoList.ReadWrite"].
    • Definieer protectedAPIScopes2 met scopes voor de tweede API, vergelijkbaar met protectedAPIScopes1.
    • Declareer de optionele tekenreeksvariabelen accessTokenAPI1 en accessTokenAPI2.
  2. Gebruikers aanmelden met behulp van het volgende codefragment:

    @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)
    }
    

    De methode signInPressed verwerkt het indrukken van de aanmeldingsknop. Er wordt gecontroleerd of de velden voor e-mail en wachtwoord zijn ingevuld. Als een van beide leeg is, wordt 'E-mail of wachtwoord niet ingesteld' weergegeven. Als beide velden zijn ingevuld, wordt het e-mailbericht vastgelegd, wordt 'Aanmelden...' weergegeven en wordt de aanmelding gestart met behulp van de signIn methode van nativeAuth met het opgegeven e-mailadres en wachtwoord. De SDK haalt een token op dat geldig is voor de standaard OIDC-bereiken (openid, offline_access, profiel), omdat er geen bereiken zijn opgegeven.

  3. Haal een of meer toegangstokens op met behulp van het volgende codefragment:

    @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)
        }
    }
    

    De methoden protectedApi1Pressed en protectedApi2Pressed beheren het proces voor het verkrijgen van toegangstokens voor twee verschillende sets scopes. Ze zorgen er eerst voor dat de URL's en toepassingsgebieden van elke API correct zijn geconfigureerd. Als er al een toegangstoken voor de API beschikbaar is, heeft deze rechtstreeks toegang tot de API. Anders vraagt het een toegangstoken aan en informeert de gebruiker over het lopende proces voor het ophalen van tokens.

    Als u een toegangstoken wilt toewijzen aan protectedAPIScopes1 en protectedAPIScopes2, gebruikt u het volgende fragment:

    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")")
    }
    

    Met de methode onAccessTokenRetrieveCompleted wordt het toegangstoken afgedrukt op de console. Vervolgens wordt gecontroleerd of protectedAPIScopes1 zijn opgenomen in de domeinen van het resultaat en of protectedAPIUrl1 beschikbaar is; indien beschikbaar, wordt accessTokenAPI1 ingesteld en accessProtectedAPI aangeroepen met de URL en token. Er wordt een vergelijkbare controle uitgevoerd op protectedAPIScopes2 en protectedAPIUrl2, het bijwerken van accessTokenAPI2 en het maken van de API-aanroep als aan voorwaarden wordt voldaan. Ten slotte geeft de methode een bericht weer met de status van de aangemelde gebruiker, scopes en het toegangstoken, en vervolgens wordt de gebruikersinterface bijgewerkt.

    De methode onAccessTokenRetrieveError geeft een foutbericht weer met de beschrijving van de fout bij het ophalen van het toegangstoken of een standaardbericht als er geen beschrijving is opgegeven.

Een API aanroepen

Gebruik de volgende codefragmenten om een API aan te roepen:

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()
}

De accessProtectedAPI-methode verzendt een GET-aanvraag naar het opgegeven API-eindpunt met behulp van het opgegeven toegangstoken. De aanvraag wordt geconfigureerd met het token in de autorisatieheader. Wanneer het een geslaagd antwoord ontvangt (HTTP-statuscode 200-299), worden de JSON-gegevens gedeserialiseerd en wordt de gebruikersinterface bijgewerkt met de HTTP-statuscode en antwoordtekst. Als er een fout optreedt tijdens de verwerking van aanvragen of antwoorden, wordt het foutbericht weergegeven in de gebruikersinterface. Deze methode biedt toegang tot API 1 of API 2, afhankelijk van de URL en het opgegeven toegangstoken.