¿Cómo agregar autenticación a una aplicación React Native?
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.
Contents
- 1 ¿Qué es la autenticación?
- 2 Flujo de autenticación
- 3 Autenticación vs. Autorización
- 4 Beneficios de la autenticación
- 5 ¿Cómo agregar autenticación a una aplicación React Native?
- 6 Conclusión
¿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:
- Algo que sabe (por ejemplo, contraseña, PIN)
- Algo que tenga (por ejemplo, teléfono móvil, llaves)
- 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í:
- El usuario envía su contraseña al servidor.
- El servidor codifica la contraseña y la compara con el hash de contraseña en la base de datos.
- 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.
- 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ásico, inicio 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í:
¡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.
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.
A continuación, asigne a su aplicación un nombre descriptivo, deje la base de datos como NoSQL y haga clic en “Crear”.
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.
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.
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”.
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”.
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.
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>
);
}
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:
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:
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.
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
- Obtenga más información sobre la autenticación social con Google, Facebook y Apple
- 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.