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
puisque nous implémentons l'authentification par e-mail/mot de passe comme première étape, nous enregistrerons l'utilisateur.
É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) {}
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); } }
si nous fournissons toutes les entrées correctes
on en a donc fini avec la première étape
nous avons trois entrées
mais nous avons explicitement ajouté email : z.string().email() ce qui est suffisant pour ce cas d'utilisation
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) {}
C'était un test que nous avons également ajouté à nouveau
e-mail : z
.string()
.email()
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) {}
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é
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); } }
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) {}
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; } } }
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
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!