¿Cómo agregar autenticación a una aplicación React Native?

React Native (Expo) Authentication Cover

La autenticación es un componente central de casi todas las aplicaciones.

Este artículo práctico proporcionará una guía paso a paso para comenzar con la autenticación React Native.

Además de eso, describirá los conceptos básicos de la autenticación, cómo se compara con la autorización, el flujo de autenticación y los beneficios de su uso.

¿Qué es la autenticación?

La autenticación es el proceso de verificar la identidad de alguien. En términos generales, existen tres formas de autenticarse con:

  1. Algo que sabe (por ejemplo, contraseña, PIN)
  2. Algo que tenga (por ejemplo, teléfono móvil, llaves)
  3. Algo que es (por ejemplo, huella digital, iris)

La mayoría de las aplicaciones utilizan la primera opción, pero muchas combinan varias de ellas para aumentar el nivel de seguridad. Este concepto se llama autenticación multifactor (MFA, del inglés “multi-factor authentication”).

Flujo de autenticación

El flujo de autenticación genérico funciona así:

  1. El usuario envía su contraseña al servidor.
  2. El servidor codifica la contraseña y la compara con el hash de contraseña en la base de datos.
  3. Si los hashes coinciden, el servidor crea una sesión y envía el token de sesión al usuario. Por otro lado, si los hashes no coinciden, se genera un error.
  4. Luego, el usuario utiliza el token de sesión con cada solicitud. En cada solicitud, el servidor comprobará si el token está presente y es válido.

El flujo anterior es la denominada autenticación de token. Otros sistemas de autenticación incluyen JSON Web Token(JWT), autenticación de acceso básicoinicio de sesión social, etc.

Autenticación vs. Autorización

La autenticación es el acto de verificar la identidad de un usuario, mientras que la autorización es el acto de verificar si un usuario tiene permisos suficientes para realizar una acción.

Los modelos de autorización incluyen control de acceso obligatorio (MAC, del inglés “mandatory access control”), control de acceso discrecional (DAC, del inglés “discretionary access control”) y autorización basada en roles, entre otros.

Beneficios de la autenticación

Veamos algunos beneficios de usar la autenticación en sus aplicaciones móviles.

Seguridad

La autenticación puede proteger su aplicación del acceso no autorizado y garantizar que solo los usuarios legítimos tengan acceso a su servicio.

Esto ayuda a prevenir filtraciones de datos y ataques cibernéticos y mantiene el entorno de su aplicación seguro y confiable.

Personalización

La autenticación permite una experiencia de usuario personalizada dentro de la aplicación. Cuando los usuarios inician sesión, pueden acceder a configuraciones, preferencias y recomendaciones personalizadas adaptadas a sus necesidades.

Esta personalización hace que la aplicación sea más atractiva y fácil de usar. Ayuda a retener a los usuarios brindándoles una experiencia más relevante y agradable.

Requisitos legales

Las leyes de algunos países exigen que verifiques las identidades de tus usuarios. Un ejemplo de esto es Conozca a su Cliente (KYC, del inglés “Know Your Customer”).

Casi todas las aplicaciones financieras están obligadas a hacerlo. Debe tener un sistema de autenticación adecuado para cumplir con estas regulaciones o proteger la información personal de sus usuarios.

¿Cómo agregar autenticación a una aplicación React Native?

Esta parte del artículo proporcionará una guía paso a paso sobre cómo agregar la autenticación Back4app a una aplicación React Native (Expo).

Requisitos previos

  • Comprensión básica de Backend como servicio (BaaS)
  • IDE de JavaScript, Node.js y un emulador móvil o un dispositivo físico
  • Capacidad para leer y escribir código JavaScript.
  • Experiencia con React Native y Expo
  • Una cuenta de Back4app gratuita

¿Qué es Back4app?

Back4app es una de las mejores soluciones de backend como servicio (BaaS) de código abierto. Es una plataforma madura y confiable que existe desde 2015.

Sus características principales incluyen bases de datos en tiempo real, funciones de Cloud Code, generación automática de API RESTful/GraphQL y más.

Back4app tiene un panel de administración intuitivo y fácil de usar y una interfaz de línea de comandos (CLI, del inglés “command line interface”) para usuarios más avanzados.

También proporciona SDK para los marcos y lenguajes de programación más populares, como JavaScript, PHP, Flutter y Dart.

La mejor parte es que Back4app ofrece un nivel gratuito. El nivel gratuito es excelente para pruebas y creación de prototipos e incluye lo siguiente:

  • 25k/solicitudes mensuales
  • Almacenamiento de datos de 250 MB
  • Transferencia de datos de 1 GB
  • Almacenamiento de archivos de 1 GB

¿Por qué utilizar Back4app?

  • Soporta autenticación social
  • Proporciona SDK para la mayoría de los lenguajes y marcos de programación.
  • Fácil de configurar y usar
  • Excelente atención al cliente

Para saber cómo se compara la autenticación de Back4app con la autenticación de Firebase, consulte La guía definitiva para la autenticación de React Firebase.

Introducción al proyecto: introducción a la autenticación React Native

Construiremos una aplicación React Native lista para producción que utilice la autenticación Back4app. La aplicación permitirá a los usuarios registrarse, iniciar sesión y administrar sus perfiles.

Además de eso, la aplicación tendrá dos pestañas de navegación, una para usuarios autenticados y otra para usuarios no autenticados.

El producto final se verá así:

Back4app Authentication React Native App

¡Comencemos a programar!

Backend (Back4app)

En esta sección, crearemos una aplicación Back4app, ampliaremos el modelo de usuario predeterminado y obtendremos las claves API necesarias para conectarnos al backend.

Crear aplicación

Primero, inicie sesión en su cuenta Back4app o cree una si aún no la tiene.

Al iniciar sesión, será redirigido a su lista de aplicaciones. Haga clic en “Crear nueva aplicación” para crear una nueva aplicación.

Back4app App List

La plataforma Back4app le permite implementar dos tipos de aplicaciones: backend como servicio (BaaS) o contenedores como servicio (CaaS). La autenticación está incluida en el BaaS, así que selecciónela.

Back4app Backend as a Service Select

A continuación, asigne a su aplicación un nombre descriptivo, deje la base de datos como NoSQL y haga clic en “Crear”.

Back4app App Configuration

Espere aproximadamente dos minutos para que la plataforma cree la aplicación. Back4app hará todo, desde crear la capa de la aplicación hasta configurar la base de datos, la seguridad, el escalado y más.

Una vez hecho esto, serás redirigido a la interfaz de la base de datos.

Back4app Database View

Modificar base de datos

A continuación, hablemos de las clases de bases de datos.

Cada clase de base de datos Back4app viene con los siguientes campos predeterminados:

+-----------+------------+-----------------------------------------+
| Data type | Name       | Description                             |
+-----------+------------+-----------------------------------------+
| String    | objectId   | Object's unique identifier              |
+-----------+------------+-----------------------------------------+
| Date      | createdAt  | Date of object creation                 |
+-----------+------------+-----------------------------------------+
| Date      | updatedAt  | Date of object's last update            |
+-----------+------------+-----------------------------------------+
| ACL       | ACL        | Access Control List (security features) |
+-----------+------------+-----------------------------------------+

Y luego la clase Usuario viene con algunos campos adicionales:

+-----------+----------------+--------------------------+----------+
| Data type | Name           | Default value            | Required |
+-----------+----------------+--------------------------+----------+
| String    | username       |                          | yes      |
+-----------+----------------+--------------------------+----------+
| String    | email          |                          | no       |
+-----------+----------------+--------------------------+----------+
| Boolean   | emailVerified  | false                    | no       |
+-----------+----------------+--------------------------+----------+
| String    | password       |                          | yes      |
+-----------+----------------+--------------------------+----------+
| Object*   | authData       | {}                       | yes      |
+-----------+----------------+--------------------------+----------+

La clase de usuario predeterminada de Back4app debería ser buena para la mayoría de los casos de uso. Sin embargo, ampliarlo es fácil. Para demostrar cómo se hace, agreguemos un campo de biografía (bio).

Primero, haga clic en el botón “+ Columna” encima de la tabla de la base de datos.

Back4app Database Add Column

En el formulario de creación de columnas, seleccione “String” como tipo de datos, establezca el nombre en biografía, hágalo obligatorio y haga clic en “Add”.

Back4app Add Database Field

Genial, ahora sabe cómo funcionan las clases de base de datos Back4app y cómo ampliar el modelo de usuario.

Claves API

Necesitará obtener las claves API de su aplicación para conectarse al backend desde el frontend.

Para obtenerlos, navegue hasta su aplicación Back4app y seleccione “Seguridad y claves” en la barra lateral. Tome nota de la “Clave de cliente” y la “Clave de JavaScript”.

Back4app API Keys

Genial, eso es todo desde el lado del backend.

Frontend (React Native)

En esta sección, crearemos una aplicación Expo, instalaremos una biblioteca de componentes, configuraremos la navegación, nos ocuparemos de las pantallas y, por último, conectaremos el frontend con el backend.

Crear aplicación

Para crear una aplicación React Native, usaremos la utilidad create-expo-app. Esta utilidad simplifica la creación de aplicaciones React Native generando la estructura de directorios, configurando TypeScript, etc.

Primero, ejecute los siguientes comandos:

npx create-expo-app@latest back4app-expo-auth
cd back4app-expo-auth

Este comando también instalará create-expo-app si aún no la tienes

Notará que el proyecto iniciado tiene la siguiente estructura de directorios:

back4app-expo-auth/
├── app                 - Layouts, screens
├── assets              - Static assets (e.g. images, videos, fonts)
├── components          - Reusable components used through the app
├── constants           - Static variables & configurations
├── hooks               - Custom React hooks
├── scripts             - Development scripts
├── app.json            - Expo configuration & metadata
├── expo-env.d.ts       - Expo TypeScript declarations
├── ...    

Inicie el servidor de desarrollo:

$ npx expo start

Por último, presione A para abrir la aplicación en su emulador de Android. Alternativamente, puede usar el emulador de iOS o un dispositivo iOS físico. Una vez que se abre la aplicación, debería ver la pantalla Expo predeterminada.

Expo Default Screen

React Native Paper

Para simplificar el proceso de desarrollo de la interfaz de usuario, usaremos React Native Paper.

React Native Paper es una biblioteca de componentes de alta calidad y fácil de usar para aplicaciones React Native. Proporciona muchos componentes prefabricados que cubren casi todos los casos de uso.

Comience instalándolo a través de NPM:

$ npm install react-native-paper react-native-safe-area-context 

Si está compilando para iOS, también tendrá que vincular partes nativas de la biblioteca:

npx pod-install

A continuación, configure Babel para que no incluya componentes no utilizados en producción:

// babel.config.js

module.exports = function(api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    env: {
      production: {
        plugins: ["react-native-paper/babel"],
      },
    },
  };
};

Luego navegue hasta app/_layout.tsx y ajuste la aplicación en PaperProvider así:

// app/_layout.tsx

// ...

export default function RootLayout() {

  // ...

  return (
    <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
      <PaperProvider>
        <Stack>
          <Stack.Screen name="index" options={{headerShown: false}}/>
          <Stack.Screen name="(auth)" options={{headerShown: false}}/>
          <Stack.Screen name="(tabs)" options={{headerShown: false}}/>
          <Stack.Screen name="+not-found"/>
        </Stack>
      </PaperProvider>
    </ThemeProvider>
  );
}

No se olvide de la importación en la parte superior del archivo:

import {PaperProvider} from "react-native-paper";

Perfecto, hemos instalado con éxito la biblioteca de componentes.

Container

Otra cosa que haremos es crear un componente Contenedor. Este componente se utilizará en todas nuestras pantallas y agregará un margen en todos los lados para que el contenido no llegue al borde de la pantalla.

Cree un archivo Container.tsx en la carpeta de componentes:

// components/Container.tsx

import React from "react";
import {View} from "react-native";

export type ContainerProps = {
  children: React.ReactNode;
}

export function Container({children}: ContainerProps) {
  return (
    <View style={{margin: 12}}>
      {children}
    </View>
  );
}

Navegación y pantallas

Como se mencionó en la introducción del proyecto, nuestra aplicación tendrá dos pestañas de navegación.

Uno es para usuarios autenticados y el otro es para usuarios no autenticados. La pestaña “Autenticados” permitirá a los usuarios administrar sus perfiles y la otra iniciar sesión o crear una cuenta.

Para lograrlo, primero, cree la siguiente estructura de directorios:

app/
├── (auth)/
│   ├── _layout.tsx
│   ├── login.tsx
│   └── register.tsx
├── (tabs)/
│   ├── _layout.tsx
│   └── profile.tsx
├── +html.tsx
├── +not-found.tsx
├── _layout.tsx
└── index.tsx

Para obtener más información sobre Expo Router, consulte los documentos oficiales.

Los diseños de la exposición generalmente contienen una gran cantidad de código repetitivo. No quiero inundar el artículo con código, así que, por favor, tome el contenido del archivo de GitHub:

  1. (auth)/_layout.tsx
  2. (tabs)/_layout.tsx
  3. _layout.tsx

Para continuar, coloque lo siguiente en index.tsx:

// app/index.tsx

import React, {useEffect} from "react";
import {ActivityIndicator} from "react-native-paper";
import {useRouter} from "expo-router";
import {View} from "react-native";

export default function IndexScreen() {

  const router = useRouter();
  const isAuthenticated = true;

  useEffect(() => {
    setTimeout(() => {
      if (isAuthenticated) {
        router.push("profile");
      } else {
        router.push("login");
      }
    }, 1000);
  }, []);

  return (
    <View style={{
      flex: 1,
      justifyContent: "center",
      alignItems: "center",
    }}>
      <ActivityIndicator
        size="large"
        animating={true}
      />
    </View>
  );
}

El archivo index.tsx es el punto de entrada de la aplicación. En él, verificamos si el usuario está autenticado y luego lo redirigimos en consecuencia. Por ahora, la redirección se basa en la variable isAuthenticated.

Luego tome el código para las pantallas:

  1. app/(auth)/login.tsx
  2. app/(auth)/register.tsx
  3. app/(tabs)/profile.tsx

El código de las pantallas es bastante simple. Es el código React Native el que utiliza React Native Paper para crear los formularios y otras interfaces de usuario. También utiliza ganchos básicos de React como useState() y useEffect().

Parse SDK

Para conectarnos al backend usaremos Parse SDK. El SDK ofrece métodos para almacenamiento de datos, manipulación, autenticación de usuarios y más funciones.

Primero, instálelo a través de NPM:

$ npm install parse @react-native-async-storage/async-storage --save
$ npm install --save-dev @types/parse

También instalamos el paquete @react-native-async-storage/async-storage para conservar la sesión del usuario cuando se cierra la aplicación. Sin él, los usuarios tendrían que autenticarse cada vez que abran la aplicación.

Luego cree un archivo.env en la raíz del proyecto así:

EXPO_PUBLIC_APPLICATION_ID=<your-back4app-application-id>
EXPO_PUBLIC_JAVASCRIPT_KEY=<your-back4app-client-key>

Asegúrese de reemplazar <your-back4app-application-id> y <your-back4app-client-key> con claves API obtenidas en la sección backend del artículo.

Inicialice Parse en _layout.tsx así:

// app/_layout.tsx

// ...
import Parse from "parse/react-native.js";
import AsyncStorage from "@react-native-async-storage/async-storage";
import ParseContext from "@/context/parseContext";

Parse.setAsyncStorage(AsyncStorage);
Parse.initialize(
  process.env.EXPO_PUBLIC_APPLICATION_ID ?? "",
  process.env.EXPO_PUBLIC_JAVASCRIPT_KEY ?? "",
)
Parse.serverURL = "https://parseapi.back4app.com/";

async function testParse() {
  try {
    const testMessage = new Parse.Object("TestMessage");
    testMessage.set("message", "Hello, World!");
    await testMessage.save();
  } catch (error) {
    console.log("Error saving the test message: ", error);
  }
}
testParse().then(() => console.log("Successfully connected to Parse!"));

// ...

También incluimos la función testParse(), que prueba la conexión a Back4app agregando un mensaje de “¡Hola, mundo!” a la base de datos. Asegúrese de que la conexión funcione reiniciando el servidor Expo y ejecutando la aplicación en el emulador.

Back4app Database Test Message

Navegue a la vista de la base de datos de su aplicación y verifique si puede ver el mensaje.

Si recibe un error que dice “Error: crypto.getRandomValues() no es compatible”. Instale las siguientes dependencias:

npm install react-native-get-random-values --save
npm i --save-dev @types/react-native-get-random-values

Luego agregue la importación en la parte superior de _layout.tsx (antes de importar Parse):

import "react-native-get-random-values";

Reinicie el servidor de desarrollo; todo debería funcionar bien.

Para que la instancia de Parse esté disponible en todas las pantallas, la pasaremos usando React Context.

Primero, cree un directorio de contexto y coloque el siguiente archivo parseContext.ts dentro:

import {createContext} from "react";

const ParseContext = createContext<typeof Parse | null>(null);

export default ParseContext;

Luego envuelva toda la aplicación con ella mientras pasas la instancia de Parse:

// app/_layout.tsx

// ...

return (
  <ParseContext.Provider value={Parse}>
    {/* ... */}
  </ParseContext.Provider>
)

Recuperación y manipulación de datos

En esta última sección, usaremos el SDK de Parse para autenticar al usuario y obtener información del usuario.

En lugar de repetir el mismo código en cada pantalla, crearemos un gancho useParse. Este enlace recuperará la instancia de Parse del contexto, obtendrá información del usuario y activará una actualización una vez que todo esté listo.

Cree un nuevo archivo llamado useParse.ts en la carpeta context:

// context/useParse.ts

import {useContext, useEffect, useState} from "react";
import ParseContext from "@/context/parseContext";

export function useParse() {
  const parse = useContext(ParseContext) as typeof Parse;
  const [parseUser, setParseUser] = useState<Parse.User | null>(null);
  const [isParseLoaded, setIsParseLoaded] = useState(false);

  useEffect(() => {
    (async () => {
      try {
        setParseUser(await parse.User.currentAsync());
      } catch (e) {
        console.error(e);
      } finally {
        setIsParseLoaded(true);
      }
    })();

  }, []);

  return {parse, parseUser, isParseLoaded};
}

Luego modifique index.tsx reemplazando isAuthenticated con una verificación de sesión real:

// app/index.tsx

// ...
import {useParse} from "@/hooks/useParse";

export default function IndexScreen() {

  const router = useRouter();
  const {parse, parseUser, isParseLoaded} = useParse();

  useEffect(() => {
    if (!isParseLoaded) return;
    (async () => {
      if (parseUser) {
        console.log("User is authenticated!");
        console.log(parseUser.toJSON());
        router.replace("/profile");
      } else {
        console.log("User is not authenticated.");
        console.log({});
        router.replace("/(auth)/login");
      }
    })();
  }, [isParseLoaded]);

  return (
    // ...
  );
}

A continuación, modifique login.tsx para iniciar sesión como usuario:

// app/(auth)/login.tsx

// ...
import {useParse} from "@/hooks/useParse";

export default function LoginScreen() {

  const router = useRouter();
  const {parse, parseUser, isParseLoaded} = useParse();

  // ...

  const onLogin = async () => {
    // ...
    try {
      await parse.User.logIn(username, password);
      router.push("/(tabs)/profile");
    } catch (error: any) {
      setError(error.message);
    }
  }

  return (
    // ...
  );
}

Luego modifique el register.tsx de manera similar a login.tsx, pero esta vez reemplace el TODO así:

// app/(auth)/register.tsx

try {
  const user = await parse.User.signUp(username, password, undefined, undefined);
  user.setEmail(email);
  await user.save();
  router.replace("/(tabs)/profile")
} catch (error: any) {
  setError(error.message);
}

Por último, modifique profile.tsx para mostrar la información del perfil:

// app/(tabs)/profile.tsx

// ...
import {useParse} from "@/hooks/useParse";

export default function IndexScreen() {

  const router = useRouter();
  const {parse, parseUser, isParseLoaded} = useParse();

  // ...

  useEffect(() => {
    if (!parseUser) return;
    setBio(parseUser.get("bio") || "");
  }, [parseUser]);

  const onSave = async () => {
    if (!parseUser) return;
    parseUser.set("bio", bio);
    try {
      await parseUser.save();
      setSuccess("Bio saved successfully.");
    } catch (error: any) {
      setError(error.message);
    }
  }

  const onLogout = async () => {
    router.replace("/(auth)/login");
    await parse.User.logOut();
  }

  return (
    <Container>
      {!isParseLoaded ? (
        <ActivityIndicator
          size="large"
          animating={true}
        />
      ) : (
        <>
          {/* ... */}
        </>
      )}
    </Container>
  );
}

Recuerde cambiar los TODO en la llamada de devolución. Utilice {parseUser!.getUsername()} y {parseUser!.getEmail()}.

En este punto, la aplicación debería estar funcionando completamente. Reinicie el servidor de desarrollo y pruébelo creando una cuenta, iniciando sesión, cerrando sesión y cambiando su biografía. Por último, asegúrese de que los cambios se reflejen en la base de datos.

Conclusión

En conclusión, ahora sabe qué es la autenticación, sus beneficios y en qué se compara con la autorización.

Además, aprendió cómo configurar la autenticación Back4app e integrarla con una aplicación React Native (basada en Expo).

Pasos futuros

  1. Obtenga más información sobre la autenticación social con GoogleFacebook y Apple
  2. Busque en la aplicación de administración Back4app un elegante panel de administración en tiempo real

El código fuente final está disponible en GitHub.


Leave a reply

Your email address will not be published.