Introducción a AWS

Crear una aplicación iOS

Crear una aplicación iOS sencilla con AWS Amplify

Módulo 3: Agregar autenticación

En este módulo usará las CLI y bibliotecas de Amplify para configurar y agregar autenticación a su aplicación.

Introducción

La siguiente función que agregará es la autenticación de usuarios. En este módulo, aprenderá cómo autenticar un usuario con CLI y bibliotecas de Amplify, aprovechando Amazon Cognito, un proveedor de identidad de usuarios administrado.

También aprenderá a usar la interfaz de usuario alojada en Cognito para presentar un flujo completo de autenticación de usuarios, lo que permite a los usuarios registrarse, iniciar sesión y restablecer su contraseña con solo algunas líneas de código.

Utilizar una interfaz de usuarios alojada significa que la aplicación aprovecha las páginas web de Cognito para los flujos de interfaz de usuarios de registro e inicio de sesión. El usuario de la aplicación se redirige a una página web alojada en Cognito y se vuelve a dirigir a la aplicación después de registrarse. Por supuesto, Cognito y Amplify también admiten UI nativas y usted puede seguir estas instrucciones del taller para conocer más sobre la UI de autenticación personalizada.

Lo que aprenderá

  • Crear e implementar un servicio de autenticación
  • Configurar su aplicación iOS para que incluya la autenticación de UI alojada en Cognito

Conceptos clave

Bibliotecas de Amplify: las bibliotecas de Amplify le permiten interactuar con los servicios de AWS desde una aplicación web o móvil.

Autenticación: en software, la autenticación es el proceso de verificar y administrar la identidad de un usuario mediante un servicio de autenticación o API.

 Tiempo de realización

10 minutos

 Servicios utilizados

Implementación

  • Para crear el servicio de autenticación, abra una terminal y ejecute este comando:

    amplify add auth
    
    ? Do you want to use the default authentication and security configuration? Select Default configuration with Social Provider and press enter
    ? How do you want users to be able to sign in? Select the default Username and press enter
    ? Do you want to configure advanced settings? Select the default No, I am done and press enter
    ? What domain name prefix do you want to use? Select the default and press enter
    Enter your redirect signin URI: type gettingstarted:// and press enter
    ? Do you want to add another redirect signin URI? Select the default N and press enter
    Enter your redirect signout URI: type gettingstarted:// and press enter
    ? Do you want to add another redirect signout URI? Select the default N and press enter
    ? Select the social providers you want to configure for your user pool: do not select any provider and press enter

    Sabrá que la conexión es exitosa cuando visualice este mensaje (el nombre exacto del recurso puede variar):

    Successfully added resource iosgettingstartedfc5a4717 locally
  • Ahora que se ha configurado el servicio de autenticación en forma local, podemos implementarlo en la nube. En una terminal, ejecute este comando es su directorio del proyecto:

    amplify push
    
    # press Y when asked to continue

    Luego de un momento, debería ver el siguiente mensaje:

    ✔ All resources are updated in the cloud
    
    Hosted UI Endpoint: https://iosgettingstarted-dev.auth.eu-central-1.amazoncognito.com/
    Test Your Hosted UI Endpoint: https://iosgettingstarted-dev.auth.eu-central-1.amazoncognito.com/login?response_type=code&client_id=1234567890&redirect_uri=gettingstarted://
  • Antes de ir al código, agregue la biblioteca de autenticación de Amplify a las dependencias de su proyecto. Abra el archivo Podfile y agregue la línea con AmplifyPlugins/AWSCognitoAuthPlugin o copie/pegue el archivo completo a continuación.

    # you need at least version 13.0 for this tutorial, more recent versions are valid too
    platform :ios, '13.0'
    
    target 'getting started' do
      # Comment the next line if you don't want to use dynamic frameworks
      use_frameworks!
    
      # Pods for getting started
      pod 'Amplify', '~> 1.0'                             # required amplify dependency
      pod 'Amplify/Tools', '~> 1.0'                       # allows to call amplify CLI from within Xcode
    
      pod 'AmplifyPlugins/AWSCognitoAuthPlugin', '~> 1.0' # support for Cognito user authentication
    
    end

    En una terminal, ejecute el comando:

    pod install

    El comando tarda unos segundos en completarse. Debería ver esto (los números de versión reales pueden variar):

    Analyzing dependencies
    Downloading dependencies
    Installing AWSAuthCore (2.14.1)
    Installing AWSCognitoIdentityProvider (2.14.1)
    Installing AWSCognitoIdentityProviderASF (1.0.1)
    Installing AWSCore (2.14.1)
    Installing AWSMobileClient (2.14.1)
    Installing AWSPluginsCore (1.0.4)
    Installing AmplifyPlugins (1.0.4)
    Generating Pods project
    Integrating client project
    Pod installation complete! There are 3 dependencies from the Podfile and 8 total pods installed.
  • En Xcode, abra el archivo Backend.swift. En la clase Backend, realice lo siguiente:

    • Agregue una declaración de importación para AmplifyPlugins.
    • Agregue una línea al código de inicialización de Amplify que agregamos en la sección anterior.

    El bloque de código completo debería verse así:

    // at the top of the file
    import AmplifyPlugins
    
    private init () {
      // initialize amplify
      do {
         try Amplify.add(plugin: AWSCognitoAuthPlugin())
         try Amplify.configure()
         print("Initialized Amplify")
      } catch {
         print("Could not initialize Amplify: \(error)")
      }
    }

    Para verificar que todo funcione como se espera, cree el proyecto. Haga clic en el menú Product (Producto) y seleccione Build (Crear) o presione ⌘B. No debería haber ningún error.

  • El cambio de código restante rastrea el estado del usuario (¿inició sesión o no?) y activa la interfaz de usuario de SignIn/SignUp cuando el usuario no inicia sesión. 

    a. Agregue los códigos SignIn y SignOut. En cualquier lugar de la clase Backend, agregue los siguientes tres métodos:

     

    // MARK: - User Authentication
    
    // signin with Cognito web user interface
    public func signIn() {
    
        _ = Amplify.Auth.signInWithWebUI(presentationAnchor: UIApplication.shared.windows.first!) { result in
            switch result {
            case .success(_):
                print("Sign in succeeded")
            case .failure(let error):
                print("Sign in failed \(error)")
            }
        }
    }
    
    // signout
    public func signOut() {
    
        _ = Amplify.Auth.signOut() { (result) in
            switch result {
            case .success:
                print("Successfully signed out")
            case .failure(let error):
                print("Sign out failed with error \(error)")
            }
        }
    }
    
    // change our internal state, this triggers an UI update on the main thread
    func updateUserData(withSignInStatus status : Bool) {
        DispatchQueue.main.async() {
            let userData : UserData = .shared
            userData.isSignedIn = status
        }
    }

    b. Agregar un agente de escucha hub de autenticación

    A fin de seguir los cambios del estado de autenticación, agregamos un código para suscribir a los eventos de autenticación enviados por Amplify. Inicializamos el hub en el método Backend.init().

    Cuando se recibe un evento de autenticación, llamamos al método updateUserData(). Este método mantiene al objeto UserData en sincronización. La propiedad UserData.isSignedIn es @Published, lo que significa que la interfaz de usuario se actualiza automáticamente cuando cambia el valor. 

    También agregamos el código para comprobar el estado de autenticación previo al tiempo de inicio de la aplicación. Cuando la aplicación se inicia, comprueba si ya existe una sesión Cognito y, en consecuencia, actualiza la UI.

    En Backend.init (), agregue el siguiente código después de la inicialización de Amplify:

    // in private init() function
    // listen to auth events.
    // see https://github.com/aws-amplify/amplify-ios/blob/master/Amplify/Categories/Auth/Models/AuthEventName.swift
    _ = Amplify.Hub.listen(to: .auth) { (payload) in
    
        switch payload.eventName {
    
        case HubPayload.EventName.Auth.signedIn:
            print("==HUB== User signed In, update UI")
            self.updateUserData(withSignInStatus: true)
    
        case HubPayload.EventName.Auth.signedOut:
            print("==HUB== User signed Out, update UI")
            self.updateUserData(withSignInStatus: false)
    
        case HubPayload.EventName.Auth.sessionExpired:
            print("==HUB== Session expired, show sign in UI")
            self.updateUserData(withSignInStatus: false)
    
        default:
            //print("==HUB== \(payload)")
            break
        }
    }
     
    // let's check if user is signedIn or not
     _ = Amplify.Auth.fetchAuthSession { (result) in
         do {
             let session = try result.get()
                    
    // let's update UserData and the UI
         self.updateUserData(withSignInStatus: session.isSignedIn)
                    
         } catch {
              print("Fetch auth session failed with error - \(error)")
        }
    }    

    c. Actualizar el código de interfaz de usuario

    El último cambio en el código se relaciona a la interfaz de usuario; agregamos ZStack a ContentView. Dependiendo del valor de UserData.isSignedIn, la UI muestra un SigninButton o la vista de lista principal.

    Abra ContentView.swift y reemplace el cuerpo en la estructura ContentView:

    var body: some View {
    
        ZStack {
            if (userData.isSignedIn) {
                NavigationView {
                    List {
                        ForEach(userData.notes) { note in
                            ListRow(note: note)
                        }
                    }
                    .navigationBarTitle(Text("Notes"))
                    .navigationBarItems(leading: SignOutButton())
                }
            } else {
                SignInButton()
            }
        }
    }

    En el mismo archivo, agregue una vista SignInButton y una SignOutButton:

    struct SignInButton: View {
        var body: some View {
            Button(action: { Backend.shared.signIn() }){
                HStack {
                    Image(systemName: "person.fill")
                        .scaleEffect(1.5)
                        .padding()
                    Text("Sign In")
                        .font(.largeTitle)
                }
                .padding()
                .foregroundColor(.white)
                .background(Color.green)
                .cornerRadius(30)
            }
        }
    }
    
    struct SignOutButton : View {
        var body: some View {
            Button(action: { Backend.shared.signOut() }) {
                    Text("Sign Out")
            }
        }
    }

    Para verificar que todo funcione como se espera, cree el proyecto. Haga clic en el menú Product (Producto) y seleccione Build (Crear) o presione ⌘B. No debería haber ningún error.

    d. Actualizar Info.plist

    Por último, debemos garantizar que la aplicación se lance al final de la secuencia de autenticación web, proporcionada por la interfaz de usuario alojada en Cognito. Agregamos el esquema URI gettingstarted al archivo Info.plist de la aplicación.

    En Xcode, seleccione el archivo Info.plist, haga clic derecho sobre él y seleccione Open As, Source Code (Abrir como, Código fuente).

    Agregue los elementos <key> y <array> dentro del elemento <dict> superior.

    <plist version="1.0">
    
        <dict>
        <!-- YOUR OTHER PLIST ENTRIES HERE -->
    
        <!-- ADD AN ENTRY TO CFBundleURLTypes for Cognito Auth -->
        <!-- IF YOU DO NOT HAVE CFBundleURLTypes, YOU CAN COPY THE WHOLE BLOCK BELOW -->
        <key>CFBundleURLTypes</key>
        <array>
            <dict>
                <key>CFBundleURLSchemes</key>
                <array>
                    <string>gettingstarted</string>
                </array>
            </dict>
        </array>
    
        <!-- ... -->
        </dict>

    e. Crear y probar

    Para verificar que todo funcione como se espera, cree el proyecto. Haga clic en el menú Product (Producto) y seleccione Run (Ejecutar) o presione ⌘R. No debería haber ningún error. La aplicación se inicia con el botón Sign In (Iniciar sesión).

    Este es el flujo de registro completo:

Conclusión

Ahora ha agregado la autenticación del usuario a su aplicación con solo algunas líneas de código. En el siguiente módulo, agregaremos una API a su aplicación.

¿Este módulo le resultó útil?

Agregar una API de GraphQL y una base de datos