ホームページ >ウェブフロントエンド >jsチュートリアル >Passport を使用して NestJS に JWT 認証を実装する日 (パート 1)

Passport を使用して NestJS に JWT 認証を実装する日 (パート 1)

Linda Hamilton
Linda Hamiltonオリジナル
2025-01-01 10:25:10206ブラウズ

最初のステップ

ネスト g リソース認証

さらに選択を求められます
❯ REST API
GraphQL (コードファースト)
GraphQL (スキーマファースト)
マイクロサービス (非 HTTP)
WebSocket

REST API を選択すると、dtos サービス コントローラーとモジュールを使用してモジュール全体が生成されます

ユーザーの登録

最初のステップとして電子メール/パスワードベースの認証を実装しているため、ユーザーを登録します。

  1. まず検証してデータが正当であることを確認し、パスワード強度の検証を追加してブルート フォース攻撃を軽減します。
  2. データを安全に使用できるように、後でサニタイズします。
  3. ユーザー レコードがデータベースにすでに存在していることを確認します。存在する場合は、ユーザーがすでにアカウントを持っていることを意味するため、このメールがすでに登録されているという応答を送信します。
  4. 上記のチェックが失敗した場合は、ユーザーを登録する必要があることを意味します ユーザーのパスワードを取得し、bcrypt や argon2
  5. などの優れたハッシュ ライブラリを使用してハッシュします。
  6. ハッシュ化後、DBにユーザーレコードを挿入します。
  7. 電子メールが正当なものであることを確認するためにユーザーに電子メールを送信します。
  8. DDoS 攻撃を回避するためにルートにレート制限を追加します

1 受信データを検証する

nest js はクラスバリデーターのような推奨される検証パッケージと強力に統合されているため、以前の経験から、react js フロントエンドの検証ロットに zod を使用しているため、素晴らしいものを見つけました
ネスト zod と呼ばれるネスト JS エコシステムのソリューションなので、今のところはこれを使用することを好みます。始めるには、まずライブラリをインストールします
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)

これで最初のステップは完了です

データをサニタイズしましょう

3 つの入力があります

  • パスワード: 通常、パスワードはサニタイズすべきではありません。誰かが悪意のあるスクリプトをパスワードに送信したとしても、最終的にはハッシュされるため、パスワードはフロントエンドに送信され表示されることはありません。
  • は必要ありません。
  • confirmPassword: 上記と同じ話
  • 電子メール: はい 電子メールはクライアントに送信およびレンダリングされるため、インジェクションとスクリプト攻撃を軽減するために電子メールフィールドをサニタイズする必要があります

ただし、電子メール 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);
  }
}

次に、nestjs スロットル ガードをグローバル ガードとして追加します

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;
    }
  }
}

ユーザー エンドポイントの登録は機密性の高いエンドポイントのブルート フォースであるため、
または辞書攻撃が発生する可能性があるため、レート制限は厳密に保たれています

確認メールを送信する

ユーザーに確認メールを送信するための再送信は、使いやすい素晴らしいサービスです。しかし、誰もが理解しやすいように、通知サービス全体について別のエピソードを作成することにしました

以上がPassport を使用して NestJS に JWT 認証を実装する日 (パート 1)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。