Sign-In con Apple

0
803

Índice de contenidos

  • 1. Introducción
    • 1.1. Beneficios del usuario
    • 1.2. Beneficios del desarrollador
  • 2. Entorno
  • 3. Implementación
    • 3.1. Las clases.
    • 3.2. La app
  • 4. Conclusiones

 

1. Introducción

Con la salida de iOS 13, Apple ofreció una forma segura de hacer SSO basado en el Apple Id de los usuarios.

Ya estábamos acostumbrarnos a que cada vez que descargabas una aplicación que necesitase un registro de usuario, las opciones que teníamos para facilitarnos dicha tarea se basaban en redes sociales, y si no querías hacer uso de ellas, te obligan a introducir manualmente los datos del registro o login. Esto supone un problema a nuestra privacidad ya que si elegimos registrarnos con Facebook, Twitter o Google (las mas ofertadas en las aplicaciones actuales), estas empresas van a obtener información (más todavía) sobre la aplicación que nos hemos descargado y si elegimos la opción manual, tampoco estamos protegidos al 100% ya que la aplicación en la que nos registramos es conocedora de, mínimo, nuestro correo electrónico.

Pues bien, Apple solucionó todo esto de un plumazo con su propio sistema de registro, ya que podemos hacer en un solo paso y de forma completamente anónima.

1.1. Beneficios del usuario

La forma de poder hacer esto es debido a que tenemos la posibilidad de que el email con el que nos registremos sea un «alias» del nuestro, es decir, Apple va a facilitar un email generado de forma aleatoria a la app (por ejemplo: fz43vyzqed@privaterelay.appleid.com) en lugar del nuestro real, una vez hecho el registro, podremos hacer login con el mismo Id de forma completamente transparente para el usuario y con la seguridad de que Apple no rastreará la actividad del usuario.

La primera vez que la app pida el login, se abrirá un diálogo que nos pedirá un nombre y un correo electrónico, disponemos de dos opciones en este punto, enviar el real o el generado por Apple.

Tras este primer registro cada vez que la app pida el login solo va a mostrarse el dialogo de confirmación de login con Apple Id.

1.2. Beneficios del Programador

En las aplicaciones nativas, Apple nos ofrece una API muy sencilla para gestionar toda la funcionalidad en unas pocas lineas de código mediante su framework AuthenticationServices, que es compatible con todas las plataformas de Apple, incluyendo iOS, macOS, tvOS. También dispone de una API Rest para que se pueda usar en Web o en Android e incluso hay una herramienta para su implementación en Unity.

Tiene un sistema antifraude mediante aprendizaje automático de cara a identificar que la petición de registro/login es una persona real.

Dispone de un servicio «Email relay Service» para el envío de emails a los usuarios previo registro de los dominios, subdominios o correos electrónicos salientes.

Ojo! ya que implementar esta opción es OBLIGATORIO en las aplicaciones subidas a partir del 30 de Junio del 2020 siempre y cuando tu sistema de registro/login haga uso de alguna solución de terceros para este fin.

Si queremos un sistema fiable de registro/login en nuestra app, ésta es la solución, ya que nos evita tener que añadir frameworks de terceros en nuestro código. Además como dispone de solución multiplataforma no hay excusa para no implementarlo.

 

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2,3 Ghz Intel Core i9 de 8 núcleos, 32GB DDR4).
  • Sistema Operativo: Mac OS Catalina 10.15.4
  • Entorno de desarrollo: XCode 11.4.1

 

3. Implementación

3.1. Las clases

Para implementar nuestro servicio de Login con Apple únicamente vamos a necesitar conocer 4 clases:

ASAuthorizationAppleIDButton: 

Se trata del botón definido por Apple para ofrecer la funcionalidad, cualquier app que haga uso de Login con Apple y no use este botón será rechazada en la revisión. Nunca es mal momento para recordar lo estricta que es Apple con estas cosas de cara a facilitar la vida al usuario, si todas las apps que hacen uso de esta funcionalidad disponen del mismo diseño del botón, le va a ser más fácil al éste identificarlo.

ASAuthorizationAppleIDProvider

La clase que nos va a permitir formular la request de acceso.

ASAuthorizationController

El controlador que muestra al usuario para la autenticación.

ASAuthorizationAppleIDCredential

El contenedor de la información recibida tras el registro/login.

 

3.2. La app

Vamos a crear una aplicación en Xcode de tipo Single View App:

Lo primero que vamos a tener que hacer es añadir nuestra Capability, para ello seleccionamos el target de la app y seleccionamos la pestaña Signing & Capabilities, pulsamos en «+ Capability».

Ahora  buscamos la capability Sign in with Apple y la añadimos

Una vez hecho esto veremos que se ha creado un fichero .entitlements con la opción ya añadida de SignIn With Apple.

Ahora nos vamos a nuestra clase ViewController y añadimos el botón en el viewDidLoad():

import UIKit
import AuthenticationServices

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let button = ASAuthorizationAppleIDButton()
        button.center = view.center
        button.addTarget(self, action: #selector(requestAuthentication), for: .touchUpInside)
        view.addSubview(button)
    }

    @objc func requestAuthentication() {
     
    }
}

Esto nos va a colocar en el centro de la vista:

Ahora vamos a crear la request y el controlador, a la request la vamos a pasar un array de los Scopes que vamos a querer solicitar al usuario, en nuestro caso, vamos a pedirle las únicas que podemos a día de hoy, el nombre y el email:

@objc func requestAuthentication() {
        let request = ASAuthorizationAppleIDProvider().createRequest()
        request.requestedScopes = [.fullName, .email]
        
        let controller = ASAuthorizationController(authorizationRequests: [request])
        controller.delegate = self
        controller.presentationContextProvider = self
        controller.performRequests()
}

Ahora tenemos que hacer nuestro controlador delegado de presentationContextProvider y ASAuthorizationControllerDelegate, para ello vamos a crear una extensión para cada protocolo:

extension ViewController: ASAuthorizationControllerPresentationContextProviding {
    func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
        view.window!
    }
}

extension ViewController: ASAuthorizationControllerDelegate {
    
}

El protocolo ASAuthorizationControllerPresentationContextProviding nos obliga a implementar la función que indica el punto de anclaje del dialogo que se le va a mostrar al usuario, por norma general vamos a pasarle directamente el window de la aplicación, así evitamos problemas con el layout.

El protocolo ASAuthorizationControllerDelegate es el que nos va a dar las funciones en las que vamos a recibir los eventos del controlador de autorización:

extension ViewController: ASAuthorizationControllerDelegate {
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        print(authorization.credential)
    }
    
    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        print("Apple ID Authorization failed: \(error.localizedDescription)")
    }
}

En la primera función recibiremos el credencial una vez devuelto por los servicios de Apple, en la segunda vamos a recibir un error en caso de ocurra algún problema.

Para poder explorar el credencial vamos a hacer un casting a ASAuthorizationAppleIDCredential y ver los distintos valores que obtenemos:

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        print(authorization.credential)
        if let credential = authorization.credential as? ASAuthorizationAppleIDCredential {
    
            print(credential.user)
            if let email = credential.email {
                print(email)
            }
            if let fullname = credential.fullName {
                print(fullname)
            }
            if let identityToken = credential.identityToken {
                print(identityToken)
            }
            if let code = credential.authorizationCode {
                print(code)
            }
        }
}

user es el identificador único de nuestro usuario.

mail es el correo electrónico asociado a nuestro usuario, puede ser el real o el generado de forma aleatoria, según lo que haya seleccionado el usuario.

fullName es el nombre de usuario elegido por éste, en caso en lo hayamos solicitado como scope.

identityToken es el token de identificación (JWT) que contiene la siguiente información: identificador del emisor, identificador del sujeto, audiencia, tiempo de vencimiento y tiempo de emisión firmado por el servicio de identidad de Apple.

authorizationCode es el token de un solo uso para la autorización del backend, Sirve para validar los datos con el endpoint de Apple (Apple’s identity service endpoint).

Si compilamos y ejecutamos podremos iniciar el proceso de registro:

Si pulsamos en continuar y todo va bien obtendremos nuestras trazas:

000166.b7dbe1f9018c4fb5b4ea5f092e848fa4.0823
fz43vyzqed@privaterelay.appleid.com
givenName: Ignacio familyName: Acisclo 
825 bytes
63 bytes

La próxima vez que iniciemos el login, como ya se ha realizado el registro, obtendremos únicamente el user, el identityToken y el authorizationCode:

Trazas:

000166.b7dbe1f9018c4fb5b4ea5f092e848fa4.0823

825 bytes
63 bytes

Como vemos, el identificador de usuario no ha cambiado, pero los tokens obviamente serán distintos.

 

4. Conclusiones

Con unas pocas líneas hemos implementado el login con Apple en el lado cliente. Ahora que va a ser obligatorio en ciertas circunstancias, quizás es el momento de plantearse que sea el único sistema de login del que hagan uso nuestros desarrollos, de esta forma nos quitamos los problemas de implementar los SDK de terceros con la falta de control del código y los dolores de cabeza que esto supone.

Puedes descargar el proyecto aquí.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad