☰ Mục lục series
Tài liệu NestJS tiếng Việt
  1. Nhập môn (Overview)
    1. Giới thiệu
    2. First steps
    3. Controllers
    4. Providers
    5. Modules
    6. Middleware
    7. Exception filters
    8. Pipes
    9. Guards
    10. Interceptors
    11. Custom decorators
  2. Nền tảng (Fundamentals)
    1. Custom providers
    2. Asynchronous providers
    3. Dynamic modules
    4. Injection scopes
    5. Circular dependency
    6. Module reference
    7. Lazy-loading modules
    8. Execution context
    9. Lifecycle events
    10. Discovery service
    11. Platform agnosticism
    12. Testing
  3. Kỹ thuật (Techniques)
    1. Configuration
    2. Database (SQL)
    3. MongoDB
    4. Validation
    5. Caching
    6. Serialization
    7. Versioning
    8. Task scheduling
    9. Queues
    10. Logging
    11. Cookies
    12. Events
    13. Compression
    14. File upload
    15. Streaming files
    16. HTTP module
    17. Session
    18. MVC
    19. Performance (Fastify)
    20. Server-Sent Events
  4. Bảo mật (Security)
    1. Authentication
    2. Authorization
    3. Encryption & Hashing
    4. Helmet
    5. CORS
    6. CSRF
    7. Rate limiting
    8. Vòng đời request
  5. OpenAPI (Swagger)
    1. Introduction
    2. Types and parameters
    3. Operations
    4. Security
    5. Mapped types
    6. Decorators
    7. CLI plugin
    8. Other features
  6. Recipes
    1. REPL
    2. CRUD generator
    3. SWC (fast compiler)
    4. Passport (auth)
    5. Hot reload
    6. MikroORM
    7. Router module
    8. Health checks (Terminus)
    9. CQRS
    10. Prisma
    11. Serve static
    12. Commander
    13. Async local storage
  7. WebSockets
    1. Gateways
    2. Exception filters
    3. Pipes
    4. Guards
    5. Interceptors
    6. Adapters
  8. Microservices
    1. Overview
    2. Redis
    3. MQTT
    4. NATS
    5. RabbitMQ
    6. Kafka
    7. gRPC
    8. Custom transporters
    9. Exception filters
    10. Pipes
    11. Pre-request hooks
    12. Guards
    13. Interceptors
  9. GraphQL
    1. Quick start
    2. Resolvers
    3. Mutations
    4. Subscriptions
    5. Scalars
    6. Directives
    7. Interfaces
    8. Unions and enums
    9. Field middleware
    10. Mapped types
    11. Plugins
    12. Complexity
    13. Extensions
    14. CLI plugin
    15. Generating SDL
    16. Sharing models
    17. Other features
    18. Federation
  10. CLI & triển khai
    1. CLI overview
    2. Workspaces
    3. Libraries
    4. Usage
    5. Scripts
    6. Deployment
    7. Standalone apps
  11. FAQ
    1. Serverless
    2. HTTP adapter
    3. Keep-Alive connections
    4. Global path prefix
    5. Raw body
    6. Hybrid application
    7. HTTPS & multiple servers
    8. Common errors
  12. Phụ lục
    1. Bảng thuật ngữ
Bảo mật (Security)

Authentication (Xác thực)

Bản dịch từ docs.nestjs.com/security/authentication

Xác thực (authentication) là một phần thiết yếu của hầu hết ứng dụng. Có rất nhiều cách tiếp cận và chiến lược khác nhau để xử lý xác thực. Cách tiếp cận cho mỗi dự án phụ thuộc vào yêu cầu cụ thể của ứng dụng đó. Chương này trình bày một số cách tiếp cận có thể điều chỉnh cho phù hợp với nhiều loại yêu cầu khác nhau.

Hãy cùng làm rõ yêu cầu của chúng ta. Với use case này, client sẽ bắt đầu bằng việc xác thực bằng username và password. Sau khi xác thực thành công, server sẽ phát hành một JWT có thể được gửi dưới dạng bearer token trong header authorization ở các request tiếp theo để chứng minh đã xác thực. Chúng ta cũng sẽ tạo một route được bảo vệ, chỉ cho phép truy cập với những request có JWT hợp lệ.

Chúng ta sẽ bắt đầu với yêu cầu đầu tiên: xác thực người dùng. Sau đó mở rộng thêm bằng việc phát hành JWT. Cuối cùng, chúng ta sẽ tạo một route được bảo vệ để kiểm tra JWT hợp lệ trên request.

Tạo module xác thực (authentication module)

Chúng ta bắt đầu bằng việc generate một AuthModule, và trong đó là AuthService và AuthController. AuthService dùng để triển khai logic xác thực, còn AuthController dùng để expose các endpoint xác thực.

$ nest g module auth
$ nest g controller auth
$ nest g service auth

Khi triển khai AuthService, chúng ta sẽ thấy hữu ích khi đóng gói các thao tác liên quan đến user vào một UsersService, vậy hãy generate module và service đó ngay bây giờ:

$ nest g module users
$ nest g service users

Thay nội dung mặc định của các file vừa generate như dưới đây. Với app mẫu này, UsersService chỉ đơn giản duy trì một danh sách user hard-code trong bộ nhớ, cùng một method find để tìm một user theo username. Trong ứng dụng thực tế, đây là nơi bạn sẽ xây dựng user model và lớp persistence (lưu trữ dữ liệu), sử dụng thư viện bạn chọn (ví dụ: TypeORM, Sequelize, Mongoose, v.v.).

import { Injectable } from '@nestjs/common';

// This should be a real class/interface representing a user entity
export type User = any;

@Injectable()
export class UsersService {
  private readonly users = [
    {
      userId: 1,
      username: 'john',
      password: 'changeme',
    },
    {
      userId: 2,
      username: 'maria',
      password: 'guess',
    },
  ];

  async findOne(username: string): Promise<User | undefined> {
    return this.users.find(user => user.username === username);
  }
}
import { Injectable } from '@nestjs/common';

@Injectable()
export class UsersService {
  constructor() {
    this.users = [
      {
        userId: 1,
        username: 'john',
        password: 'changeme',
      },
      {
        userId: 2,
        username: 'maria',
        password: 'guess',
      },
    ];
  }

  async findOne(username) {
    return this.users.find(user => user.username === username);
  }
}

Trong UsersModule, thay đổi duy nhất cần thiết là thêm UsersService vào mảng exports của decorator @Module để nó có thể được nhìn thấy từ bên ngoài module này (chúng ta sẽ dùng đến nó trong AuthService ngay sau đây).

import { Module } from '@nestjs/common';
import { UsersService } from './users.service.js';

@Module({
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}
import { Module } from '@nestjs/common';
import { UsersService } from './users.service.js';

@Module({
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

Triển khai endpoint “Sign in” (đăng nhập)

AuthService có nhiệm vụ lấy thông tin user và xác minh password. Chúng ta tạo method signIn() cho mục đích này. Trong đoạn code dưới đây, ta dùng spread operator (toán tử trải) tiện lợi của ES6 để loại bỏ property password khỏi object user trước khi trả về. Đây là thực hành phổ biến khi trả về object user, vì bạn không muốn để lộ các field nhạy cảm như password hay các key bảo mật khác.

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UsersService } from '../users/users.service.js';

@Injectable()
export class AuthService {
  constructor(private readonly usersService: UsersService) {}

  async signIn(username: string, pass: string): Promise<any> {
    const user = await this.usersService.findOne(username);
    if (user?.password !== pass) {
      throw new UnauthorizedException();
    }
    const { password, ...result } = user;
    // TODO: Generate a JWT and return it here
    // instead of the user object
    return result;
  }
}
import { Injectable, Dependencies, UnauthorizedException } from '@nestjs/common';
import { UsersService } from '../users/users.service.js';

@Injectable()
@Dependencies(UsersService)
export class AuthService {
  constructor(usersService) {
    this.usersService = usersService;
  }

  async signIn(username: string, pass: string) {
    const user = await this.usersService.findOne(username);
    if (user?.password !== pass) {
      throw new UnauthorizedException();
    }
    const { password, ...result } = user;
    // TODO: Generate a JWT and return it here
    // instead of the user object
    return result;
  }
}

Cảnh báo Tất nhiên trong ứng dụng thực tế, bạn không nên lưu password ở dạng plain text (văn bản thô). Thay vào đó, hãy dùng một thư viện như bcrypt, với thuật toán hash một chiều có salt (salted one-way hash algorithm). Với cách này, bạn chỉ lưu password đã hash, rồi so sánh password đã lưu với bản hash của password vừa gửi lên, nhờ đó không bao giờ lưu hay để lộ password gốc của user. Để giữ app mẫu đơn giản, ở đây chúng ta phá vỡ nguyên tắc bắt buộc đó và dùng plain text. Đừng làm vậy trong app thực tế của bạn!

Bây giờ, cập nhật AuthModule để import UsersModule.

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service.js';
import { AuthController } from './auth.controller.js';
import { UsersModule } from '../users/users.module.js';

@Module({
  imports: [UsersModule],
  providers: [AuthService],
  controllers: [AuthController],
})
export class AuthModule {}
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service.js';
import { AuthController } from './auth.controller.js';
import { UsersModule } from '../users/users.module.js';

@Module({
  imports: [UsersModule],
  providers: [AuthService],
  controllers: [AuthController],
})
export class AuthModule {}

Với thay đổi này, hãy mở AuthController và thêm method signIn() vào đó. Method này sẽ được client gọi để xác thực user. Nó sẽ nhận username và password trong request body, và trả về một JWT token nếu user xác thực thành công.

import { Body, Controller, Post, HttpCode, HttpStatus } from '@nestjs/common';
import { AuthService } from './auth.service.js';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @HttpCode(HttpStatus.OK)
  @Post('login')
  signIn(@Body() signInDto: Record<string, any>) {
    return this.authService.signIn(signInDto.username, signInDto.password);
  }
}

Gợi ý Về mặt lý tưởng, thay vì dùng type Record<string, any>, chúng ta nên dùng một DTO class để định nghĩa cấu trúc của request body. Xem chương validation (kiểm tra dữ liệu) để biết thêm thông tin.

JWT token

Chúng ta đã sẵn sàng chuyển sang phần JWT của hệ thống xác thực. Hãy cùng rà soát và làm rõ thêm yêu cầu:

  • Cho phép user xác thực bằng username/password, trả về JWT để dùng cho các lần gọi tiếp theo tới các API endpoint được bảo vệ. Chúng ta đã đi được nửa đường để đáp ứng yêu cầu này. Để hoàn tất, ta cần viết code phát hành JWT.
  • Tạo các API route được bảo vệ dựa trên việc có JWT hợp lệ dưới dạng bearer token hay không

Chúng ta cần cài thêm một package để hỗ trợ yêu cầu JWT:

$ npm install --save @nestjs/jwt

Gợi ý Package @nestjs/jwt (xem thêm tại đây) là một package hỗ trợ xử lý JWT. Bao gồm cả việc generate và verify (xác minh) JWT token.

Để giữ các service của mình được module hóa rõ ràng, chúng ta sẽ xử lý việc generate JWT trong authService. Mở file auth.service.ts trong thư mục auth, inject JwtService, và cập nhật method signIn để generate một JWT token như dưới đây:

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UsersService } from '../users/users.service.js';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
  constructor(
    private usersService: UsersService,
    private jwtService: JwtService
  ) {}

  async signIn(
    username: string,
    pass: string,
  ): Promise<{ access_token: string }> {
    const user = await this.usersService.findOne(username);
    if (user?.password !== pass) {
      throw new UnauthorizedException();
    }
    const payload = { sub: user.userId, username: user.username };
    return {
      // 💡 Ở đây, secret key dùng để ký (sign) payload JWT
      // chính là key đã được truyền vào JwtModule
      access_token: await this.jwtService.signAsync(payload),
    };
  }
}
import { Injectable, Dependencies, UnauthorizedException } from '@nestjs/common';
import { UsersService } from '../users/users.service.js';
import { JwtService } from '@nestjs/jwt';

@Dependencies(UsersService, JwtService)
@Injectable()
export class AuthService {
  constructor(usersService, jwtService) {
    this.usersService = usersService;
    this.jwtService = jwtService;
  }

  async signIn(username, pass) {
    const user = await this.usersService.findOne(username);
    if (user?.password !== pass) {
      throw new UnauthorizedException();
    }
    const payload = { username: user.username, sub: user.userId };
    return {
      // 💡 Ở đây, secret key dùng để ký (sign) payload JWT
      // chính là key đã được truyền vào JwtModule
      access_token: await this.jwtService.signAsync(payload),
    };
  }
}

Chúng ta đang dùng thư viện @nestjs/jwt, thư viện này cung cấp hàm signAsync() để generate JWT từ một tập con các property của object user, sau đó trả về dưới dạng một object đơn giản chỉ có một property access_token. Lưu ý: chúng ta chọn tên property sub để chứa giá trị userId cho nhất quán với chuẩn JWT.

Giờ chúng ta cần cập nhật AuthModule để import các dependency mới và cấu hình JwtModule.

Đầu tiên, tạo file constants.ts trong thư mục auth, và thêm code sau:

export const jwtConstants = {
  secret: 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
};
export const jwtConstants = {
  secret: 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
};

Chúng ta sẽ dùng file này để chia sẻ key giữa các bước ký (signing) và xác minh (verifying) JWT.

Cảnh báo Không để lộ key này ra công khai. Chúng ta viết trực tiếp như vậy ở đây để làm rõ code đang làm gì, nhưng trong hệ thống production bạn phải bảo vệ key này bằng các biện pháp phù hợp như secrets vault (kho lưu secret), environment variable (biến môi trường), hoặc configuration service.

Bây giờ, mở auth.module.ts trong thư mục auth và cập nhật như sau:

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service.js';
import { UsersModule } from '../users/users.module.js';
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller.js';
import { jwtConstants } from './constants.js';

@Module({
  imports: [
    UsersModule,
    JwtModule.register({
      global: true,
      secret: jwtConstants.secret,
      signOptions: { expiresIn: '60s' },
    }),
  ],
  providers: [AuthService],
  controllers: [AuthController],
  exports: [AuthService],
})
export class AuthModule {}
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service.js';
import { UsersModule } from '../users/users.module.js';
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller.js';
import { jwtConstants } from './constants.js';

@Module({
  imports: [
    UsersModule,
    JwtModule.register({
      global: true,
      secret: jwtConstants.secret,
      signOptions: { expiresIn: '60s' },
    }),
  ],
  providers: [AuthService],
  controllers: [AuthController],
  exports: [AuthService],
})
export class AuthModule {}

Gợi ý Chúng ta đăng ký JwtModule là global module để mọi thứ dễ dàng hơn. Điều này có nghĩa là chúng ta không cần import JwtModule ở bất kỳ đâu khác trong ứng dụng.

Chúng ta cấu hình JwtModule bằng register(), truyền vào một configuration object. Xem tại đây để biết thêm về JwtModule của Nest, và tại đây để biết chi tiết các option cấu hình khả dụng.

Hãy thử test các route của chúng ta bằng cURL. Bạn có thể test với bất kỳ object user nào hard-code trong UsersService.

$ # POST to /auth/login
$ curl -X POST http://localhost:3000/auth/login -d '{"username": "john", "password": "changeme"}' -H "Content-Type: application/json"
{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
$ # Note: above JWT truncated

Triển khai authentication guard (guard xác thực)

Giờ chúng ta có thể xử lý yêu cầu cuối cùng: bảo vệ endpoint bằng cách yêu cầu request phải có JWT hợp lệ. Chúng ta sẽ làm điều này bằng cách tạo một AuthGuard để bảo vệ các route.

import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private readonly jwtService: JwtService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const token = this.extractTokenFromHeader(request);
    if (!token) {
      throw new UnauthorizedException();
    }
    try {
      // 💡 Ở đây, secret key dùng để verify (xác minh) payload JWT
      // chính là key đã được truyền vào JwtModule
      const payload = await this.jwtService.verifyAsync(token);
      // 💡 Chúng ta gán payload vào request object ở đây
      // để có thể truy cập nó trong các route handler
      request['user'] = payload;
    } catch {
      throw new UnauthorizedException();
    }
    return true;
  }

  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}

Ghi chú người dịch Guard này hoạt động rất giống middleware xác thực bạn hay viết tay trong Express (đọc header Authorization, verify token, gán req.user), chỉ khác là nó chạy trong pipeline của Nest (trước khi vào route handler) và tích hợp sẵn với ExecutionContext — nhờ đó cùng một guard có thể tái sử dụng cho cả HTTP, WebSocket, hay RPC mà không cần biết chi tiết nền tảng bên dưới.

Giờ ta có thể triển khai route được bảo vệ và đăng ký AuthGuard để bảo vệ nó.

Mở file auth.controller.ts và cập nhật như dưới đây:

import {
  Body,
  Controller,
  Get,
  HttpCode,
  HttpStatus,
  Post,
  Request,
  UseGuards
} from '@nestjs/common';
import { AuthGuard } from './auth.guard.js';
import { AuthService } from './auth.service.js';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @HttpCode(HttpStatus.OK)
  @Post('login')
  signIn(@Body() signInDto: Record<string, any>) {
    return this.authService.signIn(signInDto.username, signInDto.password);
  }

  @UseGuards(AuthGuard)
  @Get('profile')
  getProfile(@Request() req) {
    return req.user;
  }
}

Chúng ta áp dụng AuthGuard vừa tạo cho route GET /profile để route này được bảo vệ.

Đảm bảo app đang chạy, và test các route bằng cURL.

$ # GET /profile
$ curl http://localhost:3000/auth/profile
{"statusCode":401,"message":"Unauthorized"}

$ # POST /auth/login
$ curl -X POST http://localhost:3000/auth/login -d '{"username": "john", "password": "changeme"}' -H "Content-Type: application/json"
{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2Vybm..."}

$ # GET /profile using access_token returned from previous step as bearer code
$ curl http://localhost:3000/auth/profile -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2Vybm..."
{"sub":1,"username":"john","iat":...,"exp":...}

Lưu ý rằng trong AuthModule, chúng ta đã cấu hình JWT có thời hạn hết hiệu lực (expiration) là 60 giây. Đây là thời hạn quá ngắn, và việc xử lý chi tiết chuyện hết hạn token và refresh (làm mới) token nằm ngoài phạm vi bài viết này. Tuy nhiên, chúng ta chọn thời hạn ngắn như vậy để minh họa một đặc tính quan trọng của JWT. Nếu bạn đợi 60 giây sau khi xác thực rồi mới gọi GET /auth/profile, bạn sẽ nhận về response 401 Unauthorized. Đó là vì @nestjs/jwt tự động kiểm tra thời gian hết hạn của JWT, giúp bạn không phải tự làm việc đó trong ứng dụng.

Vậy là chúng ta đã hoàn thành việc triển khai xác thực JWT. Các client JavaScript (như Angular/React/Vue) và các app JavaScript khác giờ có thể xác thực và giao tiếp an toàn với API Server của chúng ta.

Kích hoạt xác thực toàn cục (globally)

Nếu phần lớn endpoint của bạn cần được bảo vệ theo mặc định, bạn có thể đăng ký authentication guard làm global guard (guard toàn cục), và thay vì dùng decorator @UseGuards() trên từng controller, bạn chỉ cần đánh dấu route nào nên là public (công khai).

Đầu tiên, đăng ký AuthGuard làm global guard bằng cấu trúc sau (ở bất kỳ module nào, ví dụ trong AuthModule):

providers: [
  {
    provide: APP_GUARD,
    useClass: AuthGuard,
  },
],

Với thay đổi này, Nest sẽ tự động gắn (bind) AuthGuard vào tất cả endpoint.

Giờ chúng ta cần cung cấp một cơ chế để khai báo route nào là public. Để làm điều này, chúng ta có thể tạo một custom decorator dùng decorator factory function SetMetadata.

import { SetMetadata } from '@nestjs/common';

export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);

Trong file trên, chúng ta export hai constant. Một là metadata key tên là IS_PUBLIC_KEY, và một là decorator mới mà chúng ta gọi là Public (bạn có thể đặt tên khác như SkipAuth hay AllowAnon, tùy theo dự án của bạn).

Có @Public() decorator rồi, chúng ta có thể dùng nó để đánh dấu bất kỳ method nào, như sau:

@Public()
@Get()
findAll() {
  return [];
}

Cuối cùng, chúng ta cần AuthGuard trả về true khi tìm thấy metadata "isPublic". Để làm điều này, ta sẽ dùng class Reflector (đọc thêm tại đây).

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private readonly jwtService: JwtService, private reflector: Reflector) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) {
      // 💡 Xem điều kiện này
      return true;
    }

    const request = context.switchToHttp().getRequest();
    const token = this.extractTokenFromHeader(request);
    if (!token) {
      throw new UnauthorizedException();
    }
    try {
      // 💡 Ở đây, secret key dùng để verify (xác minh) payload JWT
      // chính là key đã được truyền vào JwtModule
      const payload = await this.jwtService.verifyAsync(token);
      // 💡 Chúng ta gán payload vào request object ở đây
      // để có thể truy cập nó trong các route handler
      request['user'] = payload;
    } catch {
      throw new UnauthorizedException();
    }
    return true;
  }

  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}

Ghi chú người dịch Cơ chế getAllAndOverride + SetMetadata này tương đương với việc bạn dùng struct tag hoặc một map metadata gắn vào route trong Go, hay attribute-based middleware skip trong các framework PHP: metadata được gắn vào handler/class lúc khai báo, và guard/middleware đọc lại nó lúc runtime qua reflection để quyết định hành vi — thay vì phải viết logic rẽ nhánh if/else rải rác trong từng route.

Tích hợp Passport

Passport là thư viện xác thực node.js phổ biến nhất, được cộng đồng biết đến rộng rãi và đã được dùng thành công trong nhiều ứng dụng production. Việc tích hợp thư viện này với ứng dụng Nest rất đơn giản nhờ module @nestjs/passport.

Để tìm hiểu cách tích hợp Passport với NestJS, xem chương này.

Ghi chú người dịch Nếu bạn từng dùng Passport thuần với Express, AuthGuard viết tay ở trên chính là bạn đang tự tay làm lại phần việc mà @nestjs/passport cung cấp sẵn dưới dạng strategy (chiến lược) — ví dụ passport-jwt, passport-local. Cách viết tay phù hợp để hiểu bản chất; trong dự án thực tế nên dùng @nestjs/passport để tận dụng các strategy có sẵn và tránh trùng lặp logic.

Ví dụ

Bạn có thể tìm phiên bản đầy đủ của code trong chương này tại đây.

Nội dung gốc: NestJS Documentation © Kamil Myśliwiec, giấy phép MIT. Bản dịch và ghi chú: Lê Văn Dũng.