Maison > interface Web > js tutoriel > Journée de mise en œuvre de l'authentification JWT dans NestJS avec Passport (partie 1)

Journée de mise en œuvre de l'authentification JWT dans NestJS avec Passport (partie 1)

Linda Hamilton
Libérer: 2025-01-01 10:25:10
original
206 Les gens l'ont consulté

Premiers pas

Authentification des ressources Nest G

Cela vous demandera en outre une sélection
❯ API REST
GraphQL (coder d'abord)
GraphQL (schéma en premier)
Microservice (non HTTP)
WebSockets

sélectionnez l'API REST et cela générera l'intégralité du module pour vous avec le contrôleur et le module de services dtos

Enregistrer un utilisateur

puisque nous implémentons l'authentification par e-mail/mot de passe comme première étape, nous enregistrerons l'utilisateur.

  1. Validez d'abord pour vous assurer que les données sont légitimes et ajoutez une validation de la force du mot de passe pour atténuer les attaques par force brute.
  2. Désinfectez ensuite pour garantir que les données peuvent être utilisées en toute sécurité.
  3. Vérifiez que l'enregistrement de l'utilisateur existe déjà dans la base de données s'il existe, cela signifie que l'utilisateur a déjà un compte alors envoyez une réponse indiquant que cet email est déjà enregistré.
  4. si les vérifications ci-dessus ont échoué, cela signifie que nous devons enregistrer un utilisateur prenez le mot de passe de l'utilisateur et hachez-le avec une bonne bibliothèque de hachage comme bcrypt ou argon2
  5. après le hachage, insérez l'enregistrement utilisateur dans la base de données.
  6. envoyer un e-mail à l'utilisateur pour vérifier que l'e-mail est légitime.
  7. ajouter une limitation de débit à la route pour éviter les attaques DDoS

1 Valider les données entrantes

Étant donné que Nest js a une forte intégration avec les packages de validation recommandés comme le validateur de classe, mais d'après mon expérience précédente, j'utilise zod pour le lot de validation dans les frontaux de React Js et j'ai donc trouvé un génial
solution pour l'écosystème nest js appelée nests zod, je préférerai donc utiliser celle-ci pour l'instant. Pour commencer, installez d'abord la bibliothèque
npm je nestjs-zod

import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';
const passwordStrengthRegex =
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
const registerUserSchema = z
  .object({
    email: z.string().email(),
    password: z
      .string()
      .min(8)
      .regex(
        passwordStrengthRegex,
        'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character',
      ),
    confirmPassword: z.string().min(8),
  })
  .refine((data) => data.password === data.confirmPassword, {
    message: 'Passwords do not match',
  });

export class RegisterUserDto extends createZodDto(registerUserSchema) {}

Copier après la connexion
Copier après la connexion

puis appliquez le tuyau de validation sur l'itinéraire

import { Controller, Post, Body, Version, UsePipes } from '@nestjs/common';
import { AuthService } from './auth.service';
import { RegisterUserDto } from './dto/register.dto';
import { ZodValidationPipe } from 'nestjs-zod';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Version('1')
  @Post()
  @UsePipes(ZodValidationPipe)
  async registerUser(@Body() registerUserDto: RegisterUserDto) {
    return await this.authService.registerUser(registerUserDto);
  }
}

Copier après la connexion
Copier après la connexion

si nous fournissons toutes les entrées correctes

Day  Implementing JWT Authentication in NestJS with Passport (Part 1)

on en a donc fini avec la première étape

Désinfectons les données

nous avons trois entrées

  • mot de passe : généralement, les mots de passe ne doivent pas être nettoyés car ils ne seront jamais envoyés et affichés sur le frontend, même si quelqu'un envoie un script malveillant au mot de passe, il sera finalement haché, ce n'est pas nécessaire
  • confirmPassword : même histoire que ci-dessus
  • e-mail : oui, les e-mails sont envoyés et rendus aux clients, le champ e-mail doit donc être Sanitize pour atténuer les injections et les attaques de script

mais nous avons explicitement ajouté email : z.string().email() ce qui est suffisant pour ce cas d'utilisation
Day  Implementing JWT Authentication in NestJS with Passport (Part 1)

mais pour ajouter une lyre de sécurité supplémentaire on peut ajouter une couche de désinfection

import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';
import * as xss from 'xss'; 

const passwordStrengthRegex =
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;

const registerUserSchema = z
  .object({
    email: z.string().transform((input) => xss.filterXSS(input)), // Sanitizing input using xss
    password: z
      .string()
      .min(8)
      .regex(
        passwordStrengthRegex,
        'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character',
      ),
    confirmPassword: z.string().min(8),
  })
  .refine((data) => data.password === data.confirmPassword, {
    message: 'Passwords do not match',
  });

export class RegisterUserDto extends createZodDto(registerUserSchema) {}

Copier après la connexion
Copier après la connexion

Day  Implementing JWT Authentication in NestJS with Passport (Part 1)

C'était un test que nous avons également ajouté à nouveau

e-mail : z
.string()
.email()

Étape3,4,5

import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';
const passwordStrengthRegex =
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
const registerUserSchema = z
  .object({
    email: z.string().email(),
    password: z
      .string()
      .min(8)
      .regex(
        passwordStrengthRegex,
        'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character',
      ),
    confirmPassword: z.string().min(8),
  })
  .refine((data) => data.password === data.confirmPassword, {
    message: 'Passwords do not match',
  });

export class RegisterUserDto extends createZodDto(registerUserSchema) {}

Copier après la connexion
Copier après la connexion

Le point principal à remarquer, je viens de renvoyer un message de réussite sans données liées
à l'utilisateur comme un identifiant ou un e-mail, car il n'a pas besoin de renvoyer des données à l'utilisateur à cette étape. après l'inscription, l'utilisateur sera redirigé vers la page de connexion pour remplir les détails, donc éviter d'envoyer des données inutiles est une bonne pratique de sécurité

Day  Implementing JWT Authentication in NestJS with Passport (Part 1)

Limitation du débit

implémenter la limitation de débit dans nestjs est très simple, il suffit d'installer nestjs/throttler, de le configurer globalement et vous avez terminé.
pour installer le package, exécutez npm i --save @nestjs/throttler

import { Controller, Post, Body, Version, UsePipes } from '@nestjs/common';
import { AuthService } from './auth.service';
import { RegisterUserDto } from './dto/register.dto';
import { ZodValidationPipe } from 'nestjs-zod';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Version('1')
  @Post()
  @UsePipes(ZodValidationPipe)
  async registerUser(@Body() registerUserDto: RegisterUserDto) {
    return await this.authService.registerUser(registerUserDto);
  }
}

Copier après la connexion
Copier après la connexion

puis ajoutez le protège-accélérateur Nestjs comme garde global

import { createZodDto } from 'nestjs-zod';
import { z } from 'zod';
import * as xss from 'xss'; 

const passwordStrengthRegex =
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;

const registerUserSchema = z
  .object({
    email: z.string().transform((input) => xss.filterXSS(input)), // Sanitizing input using xss
    password: z
      .string()
      .min(8)
      .regex(
        passwordStrengthRegex,
        'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character',
      ),
    confirmPassword: z.string().min(8),
  })
  .refine((data) => data.password === data.confirmPassword, {
    message: 'Passwords do not match',
  });

export class RegisterUserDto extends createZodDto(registerUserSchema) {}

Copier après la connexion
Copier après la connexion

et le voici

import {
  BadRequestException,
  Injectable,
  InternalServerErrorException,
} from '@nestjs/common';
import { RegisterUserDto } from './dto/register.dto';
import { PrismaService } from 'src/prismaModule/prisma.service';
import * as argon2 from 'argon2';

@Injectable()
export class AuthService {
  constructor(private readonly prismaService: PrismaService) {}
  async registerUser(registerUserDto: RegisterUserDto) {
    // data is validate and sanitized by the registerUserDto
    const { email, password } = registerUserDto;

    try {
      // check if user already exists
      const user = await this.prismaService.user.findFirst({
        where: {
          email,
        },
      });

      if (user) {
        throw new BadRequestException('user already eists ');
      }
      //if use not exists lets hash user password
      const hashedPassword = await argon2.hash(registerUserDto.password);

      // time to create user
      const userData = await this.prismaService.user.create({
        data: {
          email,
          password: hashedPassword,
        },
      });

      if (!userData) {
        throw new InternalServerErrorException(
          'some thing went wrong while registring user',
        );
      }

      // if user is created successfully then  send email to user for email varification
      return {
        success: true,
        message: 'user created successfully',
      };
    } catch (error) {
      throw error;
    }
  }
}

Copier après la connexion

puisque l'enregistrement du point de terminaison de l'utilisateur est une force brute de point de terminaison sensible
ou une attaque par dictionnaire peut se produire, nous avons gardé la limite de débit stricte

Envoyer un e-mail de vérification

pour envoyer un e-mail de vérification à un utilisateur, Resend est un service génial et facile à utiliser. mais j'ai décidé de créer un épisode séparé pour l'ensemble du service de notification afin que sa compréhension devienne plus facile pour tout le monde

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal