Utilice la arquitectura estructurada de Nest para crear API REST seguras y eficientes.

Express.js es una excelente tecnología para crear API REST seguras y sólidas; sin embargo, no proporciona una estructura predefinida. Su naturaleza minimalista le permite manejar aspectos esenciales como el enrutamiento, la organización del código y las medidas de seguridad, ya sea manualmente o aprovechando el middleware y las bibliotecas disponibles.

Por el contrario, Nest.js, creado sobre Express.js y Node.js, presenta una abstracción de nivel superior que ofrece una estructura clara, un enfoque de organización de código sólido y una implementación simplificada detalles. Esencialmente, Nest.js proporciona una arquitectura más estructurada para crear API y servicios de back-end eficientes y seguros.

Configuración de un proyecto Nest.js

Para comenzar, primero debe instalar la línea de comando (CLI) de Nest.js globalmente ejecutando el siguiente comando:

npm i -g @nestjs/cli

Una vez que se complete la instalación, continúe y cree un nuevo proyecto ejecutando:

instagram viewer
nido nuevo nido-jwt-api

A continuación, la CLI de Nest.js le pedirá que elija un administrador de paquetes para instalar las dependencias. Para este tutorial, usaremos npm, el administrador de paquetes de nodos. Seleccionar npm y espere mientras la CLI crea un proyecto Nest.js básico e instala todos los archivos de configuración necesarios y las dependencias iniciales necesarias para ejecutar la aplicación.

Después de configurar el proyecto, navegue hasta el directorio del proyecto e inicie el servidor de desarrollo.

cd nest-jwt-api
npm inicio de ejecución

Finalmente, ejecute el siguiente comando para instalar los paquetes que usaremos para este proyecto.

npm instala mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt

Puedes encontrar el código de este proyecto en este repositorio GitHub.

Configurar la conexión de la base de datos MongoDB

Configurar una base de datos MongoDB localmente o configurar un clúster MongoDB en la nube. Después de configurar la base de datos, copie la cadena URI de conexión de la base de datos, cree una .env archivo en el directorio raíz de nuestra carpeta de proyecto y pegue la cadena de conexión:

MONGO_URI="cadena de conexión"

A continuación, actualice la aplicación.módulo.ts en el origen archivo de directorio para configurar Mongoose de la siguiente manera:

importar { Módulo } de'@nestjs/común';
importar { Módulo de configuración } de'@nestjs/config';
importar { Módulo Mongoose } de'@nestjs/mangosta';
importar { Controlador de aplicaciones } de'./aplicación.controlador';
importar { Servicio de aplicaciones } de'./aplicación.servicio';
importar { Módulo de autenticación de usuario } de'./usuario-auth/usuario-auth.módulo';

@Módulo({
importaciones: [
ConfigModule.forRoot({
envFilePath: '.env',
esGlobal: verdadero,
}),
MongooseModule.forRoot (proceso.env. MONGO_URI),
Módulo de autenticación de usuario,
],
controladores: [AppController],
proveedores: [servicio de aplicaciones],
})

exportarclase Módulo de aplicación {}

El código proporcionado configura tres módulos esenciales para la aplicación Nest.js: ConfigModule para la configuración del entorno, MongooseModule para establecer la conexión MongoDB, y Módulo de autenticación de usuario para la autenticación del usuario. Tenga en cuenta que, en esta etapa, puede ocurrir un error ya que el Módulo de autenticación de usuario aún no está definido, pero lo crearemos en la siguiente sección.

Creación del módulo de autenticación de usuario

Para mantener un código limpio y bien organizado, cree un módulo de autenticación de usuario ejecutando el siguiente comando.

autenticación de usuario del módulo nest g

La herramienta Nest.js CLI genera automáticamente los archivos de módulo requeridos. Además, actualizará la aplicación.módulo.ts archivo, incorporando los cambios necesarios relacionados con el módulo de autenticación de usuarios.

Puede optar por crear los archivos de configuración del proyecto principal manualmente, sin embargo, la herramienta CLI simplifica este proceso creando automáticamente los elementos requeridos, además de actualizar los cambios en consecuencia en el aplicación.módulo.ts archivo.

Crear un esquema de usuario

Dentro de la recién creada autenticación de usuario carpeta en el origen directorio, crea un nuevo esquemas/usuario-auth.schema.ts y agregue el siguiente código para crear un esquema Mongoose para el Usuario modelo

importar { Objeto, Esquema, SchemaFactory } de'@nestjs/mangosta';
importar { Documento } de'mangosta';

@Esquema({ marcas de tiempo: verdadero })
exportarclase Usuario {
@Apuntalar()
nombre de usuario: cadena;
@Apuntalar()
contraseña: cadena;
}

exportartipo UserDocument = Usuario y Documento;
exportarconstante UserSchema = SchemaFactory.createForClass (Usuario);

Creación del servicio de autenticación de usuarios

Ahora, creemos el servicio de autenticación de usuarios que administrará la lógica de autenticación para la API REST ejecutando el siguiente comando:

autenticación de usuario del servicio nest g

Este comando creará un usuario-auth.service.ts archivo dentro del directorio user-auth. Abra este archivo y actualícelo con el siguiente código.

  1. Primero, realice las siguientes importaciones.
    importar { Inyectable, NotFoundException, Registrador, UnauthorizedException } de'@nestjs/común';
    importar { Inyectar modelo } de'@nestjs/mangosta';
    importar { Modelo } de'mangosta';
    importar { Usuario } de'./schemas/user-auth.schema';
    importar * como cripta de'bcrypt';
    importar { Servicio Jwt } de'@nestjs/jwt';
  2. Luego, crea un Servicio de autenticación de usuario clase que encapsula la funcionalidad para el registro de usuarios, el inicio de sesión y la recuperación de todas las rutas de datos de los usuarios.
@Inyectable()
exportarclase Servicio de autenticación de usuario {
privado registrador de solo lectura = nuevo Registrador (UserAuthService.name);
constructor(@InyectarModelo(Nombre de usuario) privado modelo de usuario: Modelo, privado jwtServicio: JwtServicio) {}

asíncrono registrarseUsuario (nombre de usuario: cadena, contraseña: cadena): Promesacadena }> {
intentar {
constante hash = esperar bcrypt.hash (contraseña, 10);
esperareste.userModel.create({nombre de usuario, contraseña: hash});
devolver { mensaje: 'Usuario registrado con éxito' };
} atrapar (error) {
tirarnuevoError('Ocurrió un error al registrar al usuario');
}
 }

asíncrono usuario de inicio de sesión (nombre de usuario: cadena, contraseña: cadena): Promesa<cadena> {
intentar {
constante usuario = esperareste.userModel.findOne({nombre de usuario});
si (!usuario) {
tirarnuevo Excepción no encontrada ('Usuario no encontrado');
}
constante coincidencia de contraseña = esperar bcrypt.compare (contraseña, usuario.contraseña);
si (!coincidencia de contraseña) {
tirarnuevo Excepción no autorizada ('Credenciales de acceso invalidos');
}
constante carga útil = { ID de usuario: usuario._id };
constante ficha = este.jwtService.sign (carga útil);
devolver simbólico;
} atrapar (error) {
consola.log (error);
tirarnuevo Excepción no autorizada ('Ocurrió un error al iniciar sesión');
}
}

asíncrono obtenerUsuarios(): Promesa {
intentar {
constante usuarios = esperareste.modelo de usuario.find({});
devolver usuarios;
} atrapar (error) {
este.registrador.error(`Ocurrió un error al recuperar usuarios: ${error.mensaje}`);
tirarnuevoError('Ocurrió un error al recuperar usuarios');
}
}
}

El Servicio de autenticación de usuario La clase implementa la lógica de registro de usuario, inicio de sesión y recuperación de datos de usuario. utiliza el modelo de usuario para interactuar con la base de datos y realizar las acciones requeridas, incluido el hash de la contraseña durante registro, validación de credenciales de inicio de sesión y, por último, generación de tokens JWT después de un éxito autenticación.

Implementación de la protección de autenticación

Para garantizar la seguridad de los recursos confidenciales, es crucial limitar el acceso exclusivamente a los usuarios autorizados. Esto se logra mediante la aplicación de una medida de seguridad que exige la presencia de un JWT válido en las solicitudes de API posteriores realizadas a puntos finales protegidos, en este caso, el usuarios ruta. En el autenticación de usuario directorio, crea un nuevo auth.guard.ts archivo y agregue el código a continuación.

importar { CanActivate, ExecutionContext, Inyectable, Excepción no autorizada } de'@nestjs/común';
importar { Servicio Jwt } de'@nestjs/jwt';
importar { Pedido } de'expresar';
importar { llave secreta } de'./config';

@Inyectable()
exportarclase AuthGuard implementos PuedeActivar {
constructor(privado jwtServicio: JwtServicio) {}

asíncrono canActivate (contexto: ExecutionContext): Promesa<booleano> {
constante solicitud = contexto.switchToHttp().getRequest();
constante ficha = este.extractTokenFromHeader (solicitud);
si (!token) {
tirarnuevo Excepción no autorizada();
}
intentar {
constante carga útil = esperareste.jwtService.verifyAsync (token, {
secreto: clavesecreta.secreto,
});
pedido['usuario'] = carga útil;
} atrapar {
tirarnuevo Excepción no autorizada();
}
devolververdadero;
}
privado extractTokenFromHeader (solicitud: Solicitud): cadena | indefinido {
constante [tipo, token] = request.headers.authorization?.split(' ')?? [];
devolvertipo'Portador'? simbólico: indefinido;
}
}

El código implementa un guardia, como se especifica en la documentación oficial, para proteger las rutas y garantizar que solo los usuarios autenticados con un token JWT válido puedan acceder a ellas.

Extrae el token JWT del encabezado de la solicitud, verifica su autenticidad usando el servicio jwt, y asigna la carga útil decodificada al solicitud['usuario'] propiedad para su posterior procesamiento. Si falta el token o no es válido, lanza un Excepción no autorizada para impedir el acceso a la ruta protegida.

Ahora, crea config.ts archivo en el mismo directorio y agregue el código a continuación.

exportarconstante clave secreta = {
secreto: 'VALOR SECRETO.',
};

Esta clave secreta se utiliza para firmar y verificar la autenticidad de los JWT. Es esencial almacenar el valor de la clave de forma segura para evitar el acceso no autorizado y proteger la integridad de los JWT.

Definir el controlador API

Cree un controlador que maneje los puntos finales de la API para la autenticación de usuarios.

autenticación de usuario del controlador nest g

A continuación, copie el código proporcionado en este archivo de repositorio de GitHub, y añádelo a la usuario-auth.controller.ts archivo: define los puntos finales para el registro de usuarios, el inicio de sesión y la recuperación de datos de usuarios. El UseGuards (AuthGuard) decorador se incluye para hacer cumplir la autenticación para el obtenerUsuarios endpoint, lo que garantiza que solo los usuarios autenticados tengan acceso.

Actualice el archivo user-auth.module.ts

Para reflejar los cambios realizados en el proyecto, actualice el usuario-auth.module.ts para configurar los módulos, servicios y controladores necesarios para la autenticación de usuarios.

importar { Módulo, Módulo Nest, Consumidor de Middleware } de'@nestjs/común';
importar { Módulo Jwt } de'@nestjs/jwt';
importar { Controlador de autenticación de usuario } de'./usuario-autorización.controlador';
importar { Servicio de autenticación de usuario } de'./usuario-autorización.servicio';
importar { Módulo Mongoose } de'@nestjs/mangosta';
importar { Esquema de usuario } de'./schemas/user-auth.schema';
importar { llave secreta } de'./config';

@Módulo({
importaciones: [
MongooseModule.forFeature([{ nombre: 'Usuario', esquema: UserSchema }]),
JwtModule.registro({
secreto: clavesecreta.secreto,
signOptions: { expiraIn: '1h' },
}),
],
controladores: [UserAuthController],
proveedores: [Servicio de autenticación de usuario],
})

exportarclase Módulo de autenticación de usuario implementos Módulo nido {
configure (consumidor: MiddlewareConsumer) {
}
}

Finalmente, ponga en marcha el servidor de desarrollo y pruebe los extremos de la API con Postman.

npm inicio de ejecución

Creación de API REST Nest.js seguras

La creación de API REST de Nest.js seguras requiere un enfoque integral que va más allá de simplemente confiar en los JWT para la autenticación y la autorización. Si bien los JWT son importantes, es igualmente crucial implementar medidas de seguridad adicionales.

Además, al priorizar la seguridad en cada etapa del desarrollo de la API, puede garantizar la seguridad de sus sistemas back-end.