Tutorial: Llamada a una API en una aplicación iOS/macOS mediante la autenticación nativa
Se aplica a: iOS (Swift) macOS (Swift)
En este tutorial, aprenderás a adquirir un token de acceso y a llamar a una API en la aplicación móvil iOS/macOS. El SDK de autenticación nativa de la biblioteca de autenticación de Microsoft (MSAL) para iOS/macOS te permite adquirir varios tokens de acceso con un inicio de sesión único. Esta funcionalidad te permite adquirir uno o varios tokens de acceso sin necesidad de que un usuario vuelva a autenticarse.
En este tutorial, aprenderás a:
- Adquirir uno o varios tokens de acceso.
- Llamada a una API
Requisitos previos
- Completa los pasos que se describen en Inicio de sesión de usuarios y llamada a una API en una aplicación móvil iOS de muestra mediante la autenticación nativa.
- Completa los pasos descritos en Tutorial: Incorporación de inicio y cierre de sesión en la aplicación iOS/macOS mediante la autenticación nativa. En este tutorial se muestra cómo iniciar la sesión de los usuarios en la aplicación iOS/macOS mediante la autenticación nativa.
Adquiere uno o varios tokens de acceso.
El SDK de autenticación nativa de MSAL puede almacenar varios tokens de acceso. Después de iniciar sesión, puedes obtener un token de acceso usando la función getAccessToken(scope:)
y especificando los ámbitos para el nuevo token de acceso que quieres conceder.
Declara y establece valores para un conjunto de ámbitos de API mediante el siguiente fragmento de código:
let protectedAPIUrl1: String? = nil let protectedAPIUrl2: String? = nil let protectedAPIScopes1: [String] = [] let protectedAPIScopes2: [String] = [] var accessTokenAPI1: String? var accessTokenAPI2: String?
- Inicializa
protectedAPIUrl1
con la dirección URL de la primera API web. - Inicializa
protectedAPIUrl2
con la dirección URL de la segunda API web. - Define
protectedAPIScopes1
con ámbitos para la primera API, como["api://<Resource_App_ID>/ToDoList.Read", "api://<Resource_App_ID>/ToDoList.ReadWrite"]
. - Define
protectedAPIScopes2
con ámbitos para la segunda API, similar aprotectedAPIScopes1
. - Declara las variables de cadena opcionales
accessTokenAPI1
yaccessTokenAPI2
.
- Inicializa
Inicia sesión del usuario mediante el siguiente fragmento de código:
@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) }
El método
signInPressed
controla la pulsación del botón de inicio de sesión. Comprueba si han rellenado los campos de correo electrónico y contraseña. Si alguno de los campos está vacío, muestra "Correo electrónico o contraseña no establecida". Si ambos campos se han rellenado, registra el correo electrónico, muestra "Iniciando sesión..." e inicia el inicio de sesión con el métodonativeAuth
designIn
con el correo electrónico y la contraseña proporcionados. El SDK recupera un token válido para los ámbitos OIDC predeterminados (openid, offline_access y profile) porque no se especifica ningún ámbito.Adquiere uno o varios tokens de acceso mediante el siguiente fragmento de código:
@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) } }
Los métodos
protectedApi1Pressed
yprotectedApi2Pressed
administran el proceso de adquisición de tokens de acceso para dos conjuntos distintos de ámbitos. Primero garantizan que la dirección URL y los ámbitos de cada API estén configurados correctamente. Si ya hay disponible un token de acceso para la API, accede directamente a la API. De lo contrario, solicita un token de acceso e informa al usuario sobre el proceso de recuperación de tokens en curso.Para asignar un token de acceso a
protectedAPIScopes1
yprotectedAPIScopes2
, usa el siguiente fragmento de código: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")") }
El método
onAccessTokenRetrieveCompleted
imprime el token de acceso en la consola. Luego, comprueba si los objetosprotectedAPIScopes1
se incluyen en los ámbitos del resultado y siprotectedAPIUrl1
está disponible; si es así, se estableceaccessTokenAPI1
y llama aaccessProtectedAPI
con la dirección URL y el token. Realiza una comprobación similar deprotectedAPIScopes2
yprotectedAPIUrl2
, actualizandoaccessTokenAPI2
y realizando la llamada API si se cumplen las condiciones. Por último, el método muestra un mensaje con el estado de inicio de sesión, los ámbitos y el token de acceso, y actualiza la IU.El método
onAccessTokenRetrieveError
muestra un mensaje de error con la descripción del error de recuperación del token de acceso o un mensaje predeterminado si no se proporciona ninguna descripción.
Llamada a una API
Usa los fragmentos de código siguientes para llamar a una 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()
}
El método accessProtectedAPI
envía una solicitud GET al punto de conexión de API especificado mediante el token de acceso proporcionado. Configura la solicitud con el token en el encabezado de autorización. Cuando recibe una respuesta correcta (código de estado de HTTP 200-299), deserializa los datos JSON y actualiza la IU con el código de estado de HTTP y el cuerpo de la respuesta. Si se produce un error durante el control de solicitudes o respuestas, muestra el mensaje de error en la IU. Este método permite el acceso a la API 1 o a la API 2, según la dirección URL y el token de acceso proporcionados.