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

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

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

第一步

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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

登录后复制
登录后复制

然后在路线上应用验证管道

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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)

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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作为全局守卫

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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

登录后复制
登录后复制

就是这里

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

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

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