首页 > web前端 > js教程 > 在 NestJS 中使用 Passport 实现 JWT 身份验证日(第 1 部分)

在 NestJS 中使用 Passport 实现 JWT 身份验证日(第 1 部分)

Linda Hamilton
发布: 2025-01-01 10:25:10
原创
194 人浏览过

第一步

nest g 资源授权

这将进一步要求您进行选择
❯ REST API
GraphQL(代码优先)
GraphQL(模式优先)
微服务(非 HTTP)
WebSocket

选择 REST API,这将为您生成带有 dtos 服务控制器和模块的整个模块

注册用户

由于我们实施基于电子邮件/密码的身份验证作为第一步,我们将注册用户。

  1. 首先验证以确保数据合法,并添加密码强度验证以减轻暴力攻击。
  2. 之后进行消毒,以确保数据可以安全使用。
  3. 检查数据库中是否已存在该用户记录,如果存在,则表示该用户已经拥有帐户,因此请发送此电子邮件已注册的回复。
  4. 如果上述检查失败,则意味着我们需要注册一个用户 获取用户密码并使用良好的哈希库(如 bcrypt 或 argon2
  5. )对其进行哈希处理
  6. 散列后将用户记录插入数据库。
  7. 向用户发送电子邮件以验证电子邮件是否合法。
  8. 为路由添加速率限制以避免 DDoS 攻击

1 验证传入数据

由于 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);
  }
}

登录后复制
登录后复制

如果我们提供的所有输入均正确

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

这样我们就完成了第一步

让我们清理数据

我们有三个输入

  • 密码:通常密码不应该被清理,因为它们永远不会发送并显示到前端,即使有人向密码发送恶意脚本,最终它也会被散列,不需要
  • 确认密码:与上面的故事相同
  • 电子邮件:是的,电子邮件会发送并呈现给客户端,因此电子邮件字段必须进行清理以减轻注入和脚本攻击

但是我们明确添加了电子邮件:z.string().email(),这对于这个用例来说已经足够了
Day  Implementing JWT Authentication in NestJS with Passport (Part 1)

但是为了增加额外的安全性,我们可以添加一个消毒层

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) {}

登录后复制
登录后复制

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

这是我们再次添加回来的测试

电子邮件:z
.string()
.email()

步骤3,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) {}

登录后复制
登录后复制

需要注意的要点我刚刚返回了一条成功消息,没有相关数据
像 ID 或电子邮件一样向用户发送,因为在此步骤中不需要向用户发送回数据。注册后,用户将被重定向到登录页面以填写详细信息,因此避免发送不必要的数据是一个很好的安全实践

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

速率限制

在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中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板