Habilitación de la autenticación en una aplicación de iOS Swift propia mediante Azure AD B2C

En este artículo se muestra cómo agregar la autenticación de Azure Active Directory B2C (Azure AD B2C) a su propia aplicación móvil Swift para iOS. Aprenda a integrar una aplicación de iOS Swift con la biblioteca de autenticación de Microsoft (MSAL) para iOS.

Use este artículo junto con el artículo Configuración de la autenticación en una aplicación Swift para iOS de ejemplo cuando sustituya la aplicación Swift para iOS de ejemplo por la suya propia. Una vez seguidas las instrucciones de este artículo, la aplicación va a aceptar inicios de sesión mediante Azure AD B2C.

Requisitos previos

Revise los requisitos previos y las instrucciones de integración de Configuración de la autenticación en una aplicación Swift de iOS de ejemplo mediante Azure Active Directory B2C.

Creación de un proyecto de aplicación Swift para iOS

Si aún no tiene una aplicación de iOS Swift, siga estos pasos para configurar un nuevo proyecto:

  1. Abra Xcode y seleccione Archivo>Nuevo>Proyecto.
  2. En el caso de las aplicaciones iOS, seleccione iOS>Aplicación y luego Siguiente.
  3. En Choose options for your new project (Elegir opciones para el nuevo proyecto), indique lo siguiente:
    1. Product name (Nombre de producto), como MSALiOS.
    2. Organization identifier (Identificador de la organización), como contoso.com.
    3. En Interface (Interfaz), seleccione Storyboard (Guion gráfico).
    4. En Life cycle (Ciclo de vida), seleccione UIKit App Delegate (Delegar aplicación UIKit).
    5. En Language (Lenguaje), seleccione Swift.
  4. Seleccione Siguiente.
  5. Seleccione una carpeta en la que crear la aplicación y luego Crear.

Paso 1: instalación de la biblioteca MSAL

  1. Ejecute CocoaPods para instalar la biblioteca MSAL. En la misma carpeta que el archivo .xcodeproj del proyecto, si el archivo podfile no existe, cree un archivo vacío y llámelo podfile. Agregue el siguiente código al archivo podfile:

    use_frameworks!
    
    target '<your-target-here>' do
       pod 'MSAL'
    end
    
  2. Reemplace <your-target-here> por el nombre del proyecto (por ejemplo, MSALiOS). Para más información, consulte la referencia de la sintaxis de Podfile.

  3. En una ventana de terminal, vaya a la carpeta que contiene el archivo podfile y ejecute pod install para instalar la biblioteca MSAL.

  4. Después de ejecutar el comando pod install, se crea un archivo <nombreDeProyecto>.xcworkspace. Para volver a cargar el proyecto en Xcoce, cierre Xcode y abra el archivo <nombreDeProyecto>.xcworkspace.

Paso 2: establecimiento del esquema de dirección URL de la aplicación

Cuando los usuarios se autentican, Azure AD B2C envía un código de autorización a la aplicación mediante el URI de redirección configurado en el registro de aplicación de Azure AD B2C.

El formato de URI de redirección predeterminado de MSAL es msauth.[Your_Bundle_Id]://auth. Un ejemplo sería msauth.com.microsoft.identitysample.MSALiOS://auth, donde msauth.com.microsoft.identitysample.MSALiOS es el esquema de la dirección URL.

En este paso, registre el esquema de la dirección URL mediante la matriz CFBundleURLSchemes. La aplicación escucha en el esquema de dirección URL para la devolución de llamada de Azure AD B2C.

En Xcode, abra el archivo Info.plist como archivo de código fuente. En la sección <dict>, agregue el siguiente fragmento de código XML:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>msauth.com.microsoft.identitysample.MSALiOS</string>
        </array>
    </dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>msauthv2</string>
    <string>msauthv3</string>
</array>

Paso 3: incorporación del código de autenticación

El código de ejemplo se compone de una clase UIViewController. La clase:

  • Define la estructura de una interfaz de usuario.
  • Contiene información sobre el proveedor de identidades de Azure AD B2C. La aplicación usa esta información para establecer una relación de confianza con Azure AD B2C.
  • Contiene el código de autenticación para autenticar a los usuarios, adquirir tokens y validarlos.

Elija la instancia UIViewController, donde los usuarios se van a autenticar. En UIViewController, combine el código con el código que se proporciona en GitHub.

Paso 4: configuración de la aplicación de iOS Swift

Después de agregar el código de autenticación, configure la aplicación Swift para iOS con los ajustes de Azure AD B2C. Los ajustes del proveedor de identidades de Azure AD B2C se configuran en la clase UIViewController elegida en la sección anterior.

Para aprender a configurar la aplicación de iOS Swift, vea Configuración de la autenticación en una aplicación de iOS Swift de ejemplo mediante Azure AD B2C.

Paso 5: ejecución y prueba de la aplicación móvil

  1. Compile y ejecute el proyecto con un simulador de un dispositivo iOS conectado.
  2. Seleccione Iniciar sesión y regístrese o inicie sesión con la cuenta de Azure AD B2C local o la cuenta social.
  3. Después de autenticarse correctamente, se ve el nombre para mostrar en la barra de navegación.

Paso 6: personalización de los bloques de creación de código

En esta sección se describen los bloques de creación de código que permiten la autenticación de la aplicación de iOS Swift. Se enumeran los métodos de UIViewController y se habla de cómo personalizar el código.

Paso 6.1: creación de instancias de una aplicación cliente pública

Las aplicaciones cliente públicas no son de confianza para mantener los secretos de aplicación de forma segura y no tienen secretos de cliente. En viewDidLoad, cree una instancia de MSAL mediante un objeto de aplicación cliente pública.

El siguiente fragmento de código de Swift muestra cómo inicializar MSAL con un objeto de configuración MSALPublicClientApplicationConfig.

El objeto de configuración proporciona información sobre el entorno de Azure AD B2C. Por ejemplo, proporciona el Id. de cliente, el URI de redirección y la autoridad para compilar solicitudes de autenticación en Azure AD B2C. Para obtener información sobre el objeto de configuración, consulte Configuración de la aplicación móvil de ejemplo.

do {

    let signinPolicyAuthority = try self.getAuthority(forPolicy: self.kSignupOrSigninPolicy)
    let editProfileAuthority = try self.getAuthority(forPolicy: self.kEditProfilePolicy)
    
    let pcaConfig = MSALPublicClientApplicationConfig(clientId: kClientID, redirectUri: kRedirectUri, authority: signinPolicyAuthority)
    pcaConfig.knownAuthorities = [signinPolicyAuthority, editProfileAuthority]
    
    self.applicationContext = try MSALPublicClientApplication(configuration: pcaConfig)
    self.initWebViewParams()
    
    } catch {
        self.updateLoggingText(text: "Unable to create application \(error)")
    }

El método initWebViewParams configura la experiencia de la autenticación interactiva.

El siguiente fragmento de código de Swift inicializa el miembro de la clase webViewParameters con la vista web del sistema. Para obtener más información, vea Personalizar exploradores y vistas web para iOS/macOS.

func initWebViewParams() {
    self.webViewParameters = MSALWebviewParameters(authPresentationViewController: self)
    self.webViewParameters?.webviewType = .default
}

Paso 6.2: inicio de una solicitud de autorización interactiva

Una solicitud de autorización interactiva es un flujo en el que se pide a los usuarios que se registren o inicien sesión mediante la vista web del sistema. Cuando los usuarios seleccionan el botón Iniciar sesión, se llama al método authorizationButton.

El método authorizationButton prepara el objeto MSALInteractiveTokenParameters con datos relevantes sobre la solicitud de autorización. El método acquireToken usa MSALInteractiveTokenParameters para autenticar a los usuarios mediante la vista web del sistema.

El siguiente fragmento de código muestra cómo iniciar la solicitud de autorización interactiva:

let parameters = MSALInteractiveTokenParameters(scopes: kScopes, webviewParameters: self.webViewParameters!)
parameters.promptType = .selectAccount
parameters.authority = authority

applicationContext.acquireToken(with: parameters) { (result, error) in

// On error code    
guard let result = result else {
    self.updateLoggingText(text: "Could not acquire token: \(error ?? "No error information" as! Error)")
    return
}

// On success code
self.accessToken = result.accessToken
self.updateLoggingText(text: "Access token is \(self.accessToken ?? "Empty")")
}

Cuando los usuarios finalizan el flujo de autorización, de forma correcta o incorrecta, el resultado se devuelve a la clausura del método acquireToken.

El método acquireToken devuelve los objetos result y error. Use esta clausura para:

  • Actualice la interfaz de usuario de la aplicación móvil con información una vez completada la autenticación.
  • Llame a un servicio de API web con un token de acceso.
  • Controle los errores de autenticación (por ejemplo, cuando un usuario cancela el flujo de inicio de sesión).

Paso 6.3: llamada a una API web

Para llamar a una API web de autorización basada en tokens, la aplicación necesita un token de acceso válido. La aplicación hace lo siguiente:

  1. Adquiere un token de acceso con los permisos necesarios (ámbitos) para el punto de conexión de API web.
  2. Pasa el token de acceso como token de portador en el encabezado de autorización de la solicitud HTTP con este formato:
Authorization: Bearer <access-token>

Cuando los usuarios se autentican interactivamente, la aplicación obtiene un token de acceso en la clausura de acquireToken. En las llamadas API web posteriores, use el método acquire token silent (acquireTokenSilent), como se describe en esta sección.

El método acquireTokenSilent realiza estas acciones:

  1. Intenta capturar un token de acceso con los ámbitos solicitados de la caché de tokens. Si el token está presente y no ha expirado, se devuelve.
  2. Si el token no está presente en la caché de tokens o ha expirado, la biblioteca MSAL intenta usar el token de actualización para adquirir un nuevo token de acceso.
  3. Si el token de actualización no existe o ha expirado, se devuelve una excepción. En este caso, debe pedir al usuario que inicie sesión de forma interactiva.

El fragmento de código siguiente muestra cómo adquirir un token de acceso:

do {

// Get the authority using the sign-in or sign-up user flow
let authority = try self.getAuthority(forPolicy: self.kSignupOrSigninPolicy)

// Get the current account from the application context
guard let thisAccount = try self.getAccountByPolicy(withAccounts: applicationContext.allAccounts(), policy: kSignupOrSigninPolicy) else {
    self.updateLoggingText(text: "There is no account available!")
    return
}

// Configure the acquire token silent parameters
let parameters = MSALSilentTokenParameters(scopes: kScopes, account:thisAccount)
parameters.authority = authority
parameters.loginHint = "username"

// Acquire token silent
self.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) {
                
                // Start an interactive authorization code
                // Notice we supply the account here. This ensures we acquire token for the same account
                // as we originally authenticated.
                
                ...
            }
        }
        
        self.updateLoggingText(text: "Could not acquire token: \(error)")
        return
    }
    
    guard let result = result else {
        
        self.updateLoggingText(text: "Could not acquire token: No result returned")
        return
    }
    
    // On success, set the access token to the accessToken class member. 
    // The callGraphAPI method uses the access token to call a web API  
    self.accessToken = result.accessToken
    ...
}
} catch {
self.updateLoggingText(text: "Unable to construct parameters before calling acquire token \(error)")
}

El método callGraphAPI recupera el token de acceso y llama a la API web, como se muestra aquí:

@objc func callGraphAPI(_ sender: UIButton) {
    guard let accessToken = self.accessToken else {
        self.updateLoggingText(text: "Operation failed because could not find an access token!")
        return
    }
    
    let sessionConfig = URLSessionConfiguration.default
    sessionConfig.timeoutIntervalForRequest = 30
    let url = URL(string: self.kGraphURI)
    var request = URLRequest(url: url!)
    request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
    let urlSession = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: OperationQueue.main)
    
    self.updateLoggingText(text: "Calling the API....")
    
    urlSession.dataTask(with: request) { data, response, error in
        guard let validData = data else {
            self.updateLoggingText(text: "Could not call API: \(error ?? "No error information" as! Error)")
            return
        }
        
        let result = try? JSONSerialization.jsonObject(with: validData, options: [])
        
        guard let validResult = result as? [String: Any] else {
            self.updateLoggingText(text: "Nothing returned from API")
            return
        }
        
        self.updateLoggingText(text: "API response: \(validResult.debugDescription)")
        }.resume()
}

Paso 6.4: cierre de sesión de los usuarios

El cierre de sesión con MSAL quita toda la información conocida sobre los usuarios de la aplicación. Use el método de cierre de sesión para cerrar la sesión de los usuarios y actualizar la interfaz de usuario. Por ejemplo, puede ocultar elementos protegidos de la interfaz de usuario, ocultar el botón de cierre de sesión o mostrar el botón de inicio de sesión.

El siguiente fragmento de código muestra cómo cerrar la sesión de los usuarios:

@objc func signoutButton(_ sender: UIButton) {
do {
    
    
    let thisAccount = try self.getAccountByPolicy(withAccounts: applicationContext.allAccounts(), policy: kSignupOrSigninPolicy)
    
    if let accountToRemove = thisAccount {
        try applicationContext.remove(accountToRemove)
    } else {
        self.updateLoggingText(text: "There is no account to signing out!")
    }
    
    ...
    
} catch  {
    self.updateLoggingText(text: "Received error signing out: \(error)")
}
}

Pasos siguientes

Obtenga información sobre cómo: