Esercitazione: chiamare più API nell'app iOS/macOS usando l'autenticazione nativa
Si applica a: iOS (Swift) macOS (Swift)
In questa esercitazione, verrà illustrato come acquisire un token di accesso e chiamare un'API nell'app iOS/macOS. L'SDK per l'autenticazione nativa di MSAL (Microsoft Authentication Library) per iOS/macOS consente di acquisire più token di accesso da un singolo accesso. Questa funzionalità consente di acquisire uno o più token di accesso senza richiedere all'utente di eseguire nuovamente l'accesso.
In questa esercitazione apprenderai a:
- Acquisire uno o più token di accesso.
- Chiamare un'API
Prerequisiti
- Completate i passaggi in Consentire l'accesso degli utenti e chiamare un'API nell'app mobile iOS di esempio usando l'autenticazione nativa.
- Completare i passaggi in Esercitazione: aggiungere l'accesso e la disconnessione nelle app iOS/macOS usando l'autenticazione nativa. Questa esercitazione illustra come consentire l'accesso agli utenti nelle app iOS/macOS usando l'autenticazione nativa.
Acquisire uno o più token di accesso
L'SDK per l'autenticazione nativa di MSAL può memorizzare più token di accesso. Dopo aver effettuato l'accesso, è possibile ottenere un token di accesso usando la funzione getAccessToken(scope:)
e specificando gli ambiti del nuovo token di accesso che si desidera concedere.
Dichiarare e impostare i valori per un insieme di ambiti API usando il seguente frammento di codice:
let protectedAPIUrl1: String? = nil let protectedAPIUrl2: String? = nil let protectedAPIScopes1: [String] = [] let protectedAPIScopes2: [String] = [] var accessTokenAPI1: String? var accessTokenAPI2: String?
- Inizializzare
protectedAPIUrl1
con l'URL della prima API Web. - Inizializzare
protectedAPIUrl2
con l'URL della seconda API Web. - Definire
protectedAPIScopes1
con gli ambiti per la prima API, ad esempio["api://<Resource_App_ID>/ToDoList.Read", "api://<Resource_App_ID>/ToDoList.ReadWrite"]
. - Definire
protectedAPIScopes2
con gli ambiti per la seconda API, simile aprotectedAPIScopes1
. - Dichiarare le variabili stringa opzionali
accessTokenAPI1
eaccessTokenAPI2
.
- Inizializzare
Consentire l'accesso dell'utente usando il seguente frammento di codice:
@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...") nativeAuth.signIn(username: email, password: password, delegate: self) }
Il metodo
signInPressed
gestisce la pressione del pulsante di accesso. Controlla se i campi e-mail e password sono compilati. Se uno dei due campi è vuoto, verrà visualizzato il messaggio "E-mail o password non impostate". Se invece sono stati compilati entrambi i campi, l'e-mail viene registrata, viene visualizzato il messaggio "Accesso..." e viene avviata la procedura di accesso usando ilsignIn
metodonativeAuth
con l'e-mail e la password fornite. L'SDK recupera un token valido per gli ambiti OIDC predefiniti (openid, offline_access, profile) perché non sono stati specificati ambiti.Acquisire uno o più token di accesso usando il seguente frammento di codice:
@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 { accountResult?.getAccessToken(scopes: protectedAPIScopes1, 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 { accountResult?.getAccessToken(scopes: protectedAPIScopes2, delegate: self) let message = "Retrieving access token to use with API 2..." showResultText(message) print(message) } }
I metodi
protectedApi1Pressed
eprotectedApi2Pressed
gestiscono il processo di acquisizione dei token di accesso per due gruppi distinti di ambiti. Prima di tutto verificano che l'URL e gli ambiti di ciascuna API siano configurati correttamente. Se è già disponibile un token di accesso per l'API, esegue l'accesso diretto all'API. In caso contrario, viene richiesto un token di accesso e l'utente viene informato del processo di recupero del token in corso.Per assegnare un token di accesso a
protectedAPIScopes1
eprotectedAPIScopes2
, usare il seguente frammento: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")") }
Il metodo
onAccessTokenRetrieveCompleted
stampa il token di accesso nella console. Verifica quindi seprotectedAPIScopes1
è incluso negli ambiti del risultato e seprotectedAPIUrl1
è disponibile; in caso positivo, impostaaccessTokenAPI1
e chiamaaccessProtectedAPI
con l'URL e il token. Esegue un controllo simile perprotectedAPIScopes2
eprotectedAPIUrl2
, aggiornandoaccessTokenAPI2
ed effettuando la chiamata API se le condizioni vengono soddisfatte. Infine, il metodo visualizza un messaggio con lo stato di accesso, gli ambiti e il token di accesso e aggiorna l'interfaccia utente.Il metodo
onAccessTokenRetrieveError
visualizza un messaggio di errore con la descrizione dell'errore di recupero del token di accesso o un messaggio predefinito se non viene fornita alcuna descrizione.
Chiamare un'API
Usare i seguenti frammenti di codice per chiamare un'API:
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()
}
Il metodo accessProtectedAPI
invia una richiesta GET all'endpoint API specificato, usando il token di accesso fornito. Configura la richiesta con il token nell'intestazione dell'autorizzazione. Quando riceve una risposta risciuta (codice di stato HTTP 200-299), deserializza i dati JSON e aggiorna l'interfaccia utente con il codice di stato HTTP e il corpo della risposta. Se si verifica un errore durante la gestione della richiesta o della risposta, visualizza il messaggio di errore nell'interfaccia utente. Questo metodo consente di accedere all'API 1 o all'API 2, a seconda dell'URL e del token di accesso forniti.