Breaking

Post Top Ad

Your Ad Spot

martes, 10 de diciembre de 2019

Desarrollo de una API segura con NestJS: gestión de identidad

Configurar una aplicación Auth0

Uno de los requisitos para este proyecto es que solo los usuarios autenticados pueden escribir registros en la tienda. Para lograrlo de manera fácil y segura, usará Auth0 para administrar las credenciales de usuario de su aplicación.
Primero, debe crear una cuenta Auth0 gratuita si aún no tiene una.
Después de crear su cuenta, diríjase a la sección API en el Panel de Auth0 y presione el botón Crear API .
Luego, en la forma que muestra Auth0:
  • Agregue un nombre a su API. Algo así como Menú API , por ejemplo.
  • Establezca su Identificador en https://menu-api.demo.com.
  • Deje el algoritmo de firma como RS256es la mejor opción desde el punto de vista de la seguridad.
Auth0 Dashboard nuevo formulario API
Los identificadores son cadenas únicas que nos ayudan a diferenciar entre sus diferentes API. Recomendamos el uso de URL ya que facilitan la creación de identificadores únicos de manera predecible; sin embargo, estas URL nunca serán llamadas por Auth0.
Con estos valores en su lugar, presione el botón Crear .
Ahora, haga clic en la pestaña Inicio rápido . Esta página presenta instrucciones sobre cómo configurar diferentes API. En el cuadro de código, elija Node.js . Mantenga esta ventana abierta ya que usará los valores del fragmento de código a continuación.
Menú API Node.js Inicio rápido

Crear un módulo de autenticación

Como se mencionó anteriormente, usará Auth0 para administrar usuarios y credenciales. Además, utilizará la biblioteca de autenticación Passport para abstraer los matices de la implementación de la autenticación.
El flujo de autenticación es el siguiente:
  • Los usuarios comenzarán autenticándose con un nombre de usuario y contraseña administrados por Auth0.
  • Una vez autenticado, el servidor de autenticación Auth0 emitirá un JWT (JSON Web Token) al cliente llamado token de acceso .
  • Luego, el token de acceso se puede enviar como un token de portador en un encabezado de autorización para probar la autenticación al servidor en las solicitudes realizadas a puntos finales protegidos.
Creará guardias para proteger los puntos finales que escriben en la tienda. Estos guardias rechazarán cualquier solicitud que no contenga un token de acceso válido. Toda su lógica de autenticación se incluirá en un módulo denominado AuthModule.
Como antes, use la CLI de NestJS para crear su nuevo módulo de autenticación:
npx nest generate module auth
Simplemente así, NestJS crea un authdirectorio debajo del srcdirectorio y coloca un auth.module.tsarchivo dentro de él que define la estructura básica para AuthModuleSi inspecciona la AppModuledefinición, verá que NestJS se ha agregado AuthModulea su importsmatriz.
// src/app.module.ts

import { Module } from '@nestjs/common';
import { ItemsModule } from './items/items.module';
import { AuthModule } from './auth/auth.module';

@Module({
  imports: [ItemsModule, AuthModule],
  controllers: [],
  providers: [],
})
export class AppModule {}
Esto establece una dependencia del módulo y le permite usar cualquiera de las funciones expuestas de AuthModuletoda su aplicación.
¡Ahora está listo para configurar Passport y hacer que Auth0 trabaje para usted!

Usando el pasaporte con NestJS

Passport.js ofrece diferentes mecanismos de autenticación, conocidos como estrategias , para satisfacer los requisitos únicos de autenticación que tiene cada aplicación. Las estrategias se empaquetan como módulos individuales y puede elegir qué estrategias emplear, sin crear dependencias innecesarias. El @nestjs/passportmódulo envuelve estas estrategias en construcciones idiomáticas de NestJS.
Para su aplicación, creará una estrategia JSON Web Token (JWT) Passport dentro de la cual se agrupará AuthModulePara comenzar, instale las siguientes dependencias:
npm i passport @nestjs/passport passport-jwt jwks-rsa
Aquí hay un desglose de lo que hacen estos paquetes:
  • passport: Middleware de autenticación Express-compatible para Node.js.
  • @nestjs/passport: El módulo de utilidades Passport para Nest.
  • passport-jwt: Estrategia de pasaporte para la autenticación con un token web JSON (JWT).
  • jwks-rsa: Una biblioteca para recuperar claves de firma RSA de un punto final JWKS (conjunto de claves web JSON).
En realidad, Passport actúa más como un marco de autenticación que como una biblioteca. Resume el proceso de autenticación en una serie de pasos estándar que se personalizan en función de la estrategia de autenticación que se implementa. El pasaporte necesita dos elementos clave para procesar la autenticación:
  • Opciones de configuración para la estrategia.
  • Una devolución de llamada de verificación , que tiene el propósito de encontrar al usuario que posee un conjunto de credenciales. Cuando Passport autentica una solicitud, analiza las credenciales o cualquier otra información de autenticación contenida en la solicitud. Luego invoca la devolución de llamada de verificación con los datos de autenticación como argumentos, como un token de acceso, que su aplicación puede consumir.
Veamos esto en acción.
Para configurar una JwtStrategyestrategia de pasaporte, necesita dos valores de Auth0: un dominio Auth0 y una audiencia Auth0. Los colocará en su .envarchivo que se cargará dotenv.config()cuando se inicialice la estrategia:
PORT=7000
AUTH0_DOMAIN=<Your Auth0 domain>
AUTH0_AUDIENCE=<Your Auth0 audience>
Asegúrese de reemplazar los valores de marcador de posición con los valores de Auth0 correspondientes del código de inicio rápido de Node.js que vio anteriormente.
El dominio Auth0 es el valor de la issuerpropiedad sin la barra diagonal al final:
https://<Tenant Name>.auth0.com
La audiencia Auth0 es el valor de la audiencepropiedad.
No incluya las comillas como parte del .envvalor de la variable. Solo incluya la cadena dentro de las comillas.
A continuación, cree un jwt.strategy.tsarchivo en el src/authdirectorio:
touch src/auth/jwt.strategy.ts
Actualice este archivo de la siguiente manera:
// src/auth/jwt.strategy.ts

import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { passportJwtSecret } from 'jwks-rsa';
import * as dotenv from 'dotenv';

dotenv.config();

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      secretOrKeyProvider: passportJwtSecret({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: `${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`,
      }),

      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      audience: process.env.AUTH0_AUDIENCE,
      issuer: `${process.env.AUTH0_DOMAIN}/`,
      algorithms: ['RS256'],
    });
  }

  validate(payload: any) {
    return payload;
  }
}
Usando el @nestjs/passportmódulo, se crea una estrategia de Pasaporte al extender la clase abstracta devuelta por la PassportStrategyfunción . Esta función toma como argumento lo Strategyque desea implementar, que en este caso es la estrategia JWT importada de passport-jwt.
Las opciones de estrategia pasadas a través de la super()llamada dentro del le constructorpermiten analizar tokens de acceso con formato JWT y configurar su API para aceptar RS256tokens firmados.
Con el envoltorio NestJS aplicado, la devolución de llamada de verificación se convierte en el validate()método. En este caso, la implementación de validate()es muy simple porque Auth0 maneja todas las tareas de autenticación de usuario en el servidor. Cuando se llama a este método, Auth0 ya ha determinado la identidad del usuario que está iniciando sesión en su aplicación y pasa datos sobre ese usuario dentro del payloadobjeto. Esto payloadse adjunta al requestobjeto al que puede acceder cualquiera de los participantes del ciclo de solicitud-respuesta, como los controladores de su enrutador y cualquier middleware.
El siguiente paso es configurar Passport con JwtStrategyy registrarlo con AuthModuleÁbrelo src/auth/auth.module.tsy actualízalo de la siguiente manera:
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [PassportModule.register({ defaultStrategy: 'jwt' })],
  providers: [JwtStrategy],
  exports: [PassportModule],
})
export class AuthModule {}
PassportModuleImporta el , que es un contenedor NestJS en Passport, y se registra jwtcomo su estrategia predeterminada.
Tiene la mecánica para recibir un token de acceso y verificar si un usuario está autenticado o no. El siguiente paso es crear guardias que bloqueen las solicitudes no autenticadas a puntos finales protegidos utilizando el @UseGuards()decorador.

Crear guardias de punto final con NestJS

Actualice de la src/items/items.controller.tssiguiente manera:
import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Post,
  Put,
  UseGuards,
} from '@nestjs/common';
import { ItemsService } from './items.service';
import { Items } from '../items';
import { Item } from '../item';
import { AuthGuard } from '@nestjs/passport';

@Controller('items')
export class ItemsController {
  constructor(private readonly itemsService: ItemsService) {}

  @Get()
  async findAll(): Promise<Items> {
    return this.itemsService.findAll();
  }

  @Get(':id')
  async find(@Param('id') id: number): Promise<Item> {
    return this.itemsService.find(id);
  }

  @UseGuards(AuthGuard('jwt'))
  @Post()
  create(@Body('item') item: Item) {
    this.itemsService.create(item);
  }

  @UseGuards(AuthGuard('jwt'))
  @Put()
  update(@Body('item') item: Item) {
    this.itemsService.update(item);
  }

  @UseGuards(AuthGuard('jwt'))
  @Delete(':id')
  delete(@Param('id') id: number) {
    this.itemsService.delete(id);
  }
}
Veamos el POST items/punto final:
@UseGuards(AuthGuard('jwt'))
@Post()
create(@Body('item') item: Item) {
  this.itemsService.create(item);
}
Con @UseGuards(AuthGuard('jwt')), está utilizando una AuthGuardque @nestjs/passportaprovisiona automáticamente para su AuthModuleal configurar el passport-jwtmódulo en su estrategia de pasaporte, JwtStrategyEl @UseGuards()decorador hace referencia a este protector por su nombre predeterminado jwt, que coincide con el valor del defaultStrategyregistro para PassportModulela AuthModuledefinición.
Cuando realiza una solicitud al POST items/punto final protegido, la protección invoca automáticamente su JwtStrategylógica de configuración y bloquea la solicitud si el JWT no es válido o está ausente.
Pruébalo:
curl -X POST -H 'Content-Type: application/json' -d '{
  "item": {
    "name": "Salad",
    "price": 4.99,
    "description": "Fresh",
    "image": "https://cdn.auth0.com/blog/whatabyte/salad-sm.png"
  }
}' http://localhost:7000/items -i
No va a funcionar Obtendrá una 401 Unauthorizedrespuesta que indica que la solicitud fue rechazada debido a que no tiene credenciales de autenticación válidas requeridas por el recurso de destino, el POST items/punto final.
Sin embargo, hacer una solicitud al GET items/punto final funciona:
curl http://localhost:7000/items -i
Para probar la función de autenticación de su aplicación, necesitará un token de acceso válido. Un cliente, como una Aplicación de una sola página (SPA), obtendría el token de acceso realizando un inicio de sesión y luego pasando el token de acceso en un encabezado de autorización a su API. Todavía no tiene un cliente integrado, pero puede utilizar este Cliente de demostración: Panel de WHATABYTE .

Crear una aplicación de cliente Auth0

WHATABYTE es un restaurante ficticio que utiliza un tablero para administrar su menú. Puede consumir la API que ha creado hasta ahora. Para configurar este cliente, debe crear una aplicación de página única Auth0 en el panel de Auth0. Eso le dará el dominio Auth0 y el ID de cliente Auth0, lo que permitirá que esta aplicación se comunique con el servidor de autenticación Auth0 y obtenga tokens de acceso para sus usuarios registrados.
El proceso de crear una aplicación cliente Auth0 es bastante fácil:
  • Abra la sección Aplicaciones Auth0 del Panel de Auth0.
  • Haga clic en el botón Crear aplicación .
  • Proporcione un valor de Nombre como WAB Dashboard.
  • Elija Aplicaciones web de una sola página como tipo de aplicación .
  • Haz clic en el botón Crear .
En la página de la aplicación que se carga, haga clic en la pestaña Configuración . Utilice los valores de Auth0 presentes allí para completar los valores que faltan en el formulario de configuración de demostración de Auth0 del cliente del panel de control WAB , a saber, el dominio Auth0 y el ID de cliente Auth0.
Formulario de configuración de demostración del panel de WHATABYTE
Haga clic en el botón Guardar debajo del formulario. Se debería cargar la vista de inicio del panel de WAB WAB Dashboard es un cliente para su aplicación de servidor NestJS. Para probar esta conexión, haga clic en la pestaña Menú . Verá el siguiente error:
Network Error. Unable to retrieve menu information.
Si abre la consola del desarrollador del navegador, notará que se ha producido un error CORS. Sin embargo, arreglar esto es fácil con NestJS.

Habilitación de CORS en NestJS

Ábrelo src/main.tsy actualízalo de la siguiente manera:
// src/main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as dotenv from 'dotenv';
import { ValidationPipe } from '@nestjs/common';

dotenv.config();

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.enableCors();
  app.useGlobalPipes(
    new ValidationPipe({
      disableErrorMessages: true,
    }),
  );

  await app.listen(process.env.PORT);
}
bootstrap();
Llama al enableCors()método de su appinstancia para permitir que se soliciten recursos de otro dominio.
Regrese a la vista del menú del panel WAB y actualícela. Esta vez, los tres elementos disponibles en su tienda NestJS se cargan y el error CORS desaparece de la consola del desarrollador.
Todavía no puede iniciar sesión en el Tablero de WAB ya que su aplicación cliente Auth0 debe configurarse para aceptar solicitudes de autenticación de la aplicación de cliente del Tablero de WAB. Lo harás después.

Conexión de una aplicación de cliente con Auth0

Regrese a la pestaña Configuración de su aplicación cliente Auth0. Actualice los siguientes campos de configuración:

URL de devolución de llamada permitidas

Utilice el valor de Auth0 devolución de llamada URL de la configuración de demostración Auth0 forma, https://dashboard.whatabyte.now.sh/home.
Después de que un usuario se autentica, Auth0 solo devolverá la llamada a cualquiera de las URL que se enumeran allí. Puede especificar varias URL válidas separándolas por comas (generalmente para manejar diferentes entornos como control de calidad o pruebas). Asegúrese de especificar el protocolo, http: // o https: //, de lo contrario, la devolución de llamada puede fallar en algunos casos.

Orígenes web permitidos

Uso https://dashboard.whatabyte.now.sh.
Este campo contiene una lista separada por comas de orígenes permitidos para usar con el modo de respuesta de mensajes web , lo que permite iniciar sesión usando una ventana emergente, como pronto verá en la siguiente sección.

URL de cierre de sesión permitidas

Uso https://dashboard.whatabyte.now.sh/home.
Este campo contiene un conjunto de URL que son válidas para redirigir después de que un usuario cierre sesión en su aplicación. El cliente de demostración se ha configurado para usar el valor proporcionado para redirigir a los usuarios.
Una vez que estos valores estén en su lugar, desplácese hasta la parte inferior y haga clic en el botón Guardar cambios .

Iniciando sesión

Regrese al Panel de WAB y haga clic en el botón Iniciar sesión . Dado que este puede ser el primer usuario que está agregando a Auth0, continúe y haga clic en la pestaña Registrarse en la ventana emergente que aparece y proporcione un correo electrónico y una contraseña para registrar a su nuevo usuario.
Formulario de registro de Auth0
Una vez iniciada sesión, la interfaz de usuario cambia:
  • La sesión botón se convierte en una sesión fuera botón
  • Ahora se muestra una pestaña de usuario debajo del botón Cerrar sesión .
Haga clic en la pestaña de usuario y verá una página personalizada con su correo electrónico como título.
WAB Dashboard está diseñado para atender a dos tipos de usuarios: usuarios normales y usuarios con un menu-adminrol. Este rol permite al usuario crear, actualizar y eliminar elementos de menú en el Panel de WAB.
En la siguiente sección, creará el menu-adminrol, le asociará permisos y lo asignará a un nuevo usuario que creará a través del Panel de Auth0. Este usuario privilegiado podrá desbloquear las funciones de administración del panel de WAB.

Control

Agregue sus archivos de proyecto actuales al repositorio:
git add .
Confirme el paquete de archivos de la siguiente manera:

git commit -m "Secure API with Auth0 authentication"

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

Post Top Ad

Your Ad Spot

Páginas