nest g 资源授权
这将进一步要求您进行选择
❯ REST API
GraphQL(代码优先)
GraphQL(模式优先)
微服务(非 HTTP)
WebSocket
选择 REST API,这将为您生成带有 dtos 服务控制器和模块的整个模块
由于我们实施基于电子邮件/密码的身份验证作为第一步,我们将注册用户。
由于 Nest js 与类验证器等推荐的验证包有很强的集成,但根据我之前的经验,我在 React JS 前端使用 zod 进行验证,所以我发现了一个很棒的
Nest js 生态系统的解决方案称为 Nests Zod,所以我现在更喜欢使用这个。首先安装库
npm 我 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) {}
然后在路线上应用验证管道
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); } }
如果我们提供的所有输入均正确
这样我们就完成了第一步
我们有三个输入
但是我们明确添加了电子邮件:z.string().email(),这对于这个用例来说已经足够了
但是为了增加额外的安全性,我们可以添加一个消毒层
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) {}
这是我们再次添加回来的测试
电子邮件: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) {}
需要注意的要点我刚刚返回了一条成功消息,没有相关数据
像 ID 或电子邮件一样向用户发送,因为在此步骤中不需要向用户发送回数据。注册后,用户将被重定向到登录页面以填写详细信息,因此避免发送不必要的数据是一个很好的安全实践
在nestjs中实现速率限制非常简单,只需安装nestjs/throttler并进行全局配置即可。
要安装包,请运行 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); } }
然后添加nestjsthrottleguard作为全局守卫
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) {}
就是这里
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; } } }
因为注册用户端点是一个敏感端点暴力破解
否则可能会发生字典攻击,我们严格限制速率
用于向用户发送验证电子邮件的使用 Resend 是一项非常棒的易于使用的服务。但我决定为整个通知服务创建一个单独的剧集,以便每个人都更容易理解它
以上是在 NestJS 中使用 Passport 实现 JWT 身份验证日(第 1 部分)的详细内容。更多信息请关注PHP中文网其他相关文章!