NestJS

NestJS

NestJS - A progressive Node.js framework NestJS is a framework for building efficient, scalable Node.js web applications.
Iara  Simões

Iara Simões

1660408200

Como Implementar A Autenticação JWT No NestJS

A autenticação é um dos aspectos mais importantes de qualquer aplicativo. Ele melhora a segurança do aplicativo verificando os usuários antes de conceder acesso a diferentes partes do aplicativo. A autenticação também permite que as empresas acompanhem quantas pessoas estão usando seus produtos.

É de vital importância configurar a autenticação corretamente. Na verdade, o Open Web Application Security Project (OWASP)  identifica falhas de identificação e autenticação em sua lista dos dez principais riscos de segurança de aplicativos da web.

Este tutorial demonstrará o processo passo a passo para implementar a autenticação de usuário JWT no NestJS.

Pré-requisitos

Este tutorial é uma demonstração prática. Para acompanhar, verifique se você tem o seguinte instalado:

  • Node.js v14 e superior
  • MongoDB
  • Fio instalado globalmente; use o comandonpm install --global yarn

O que é NestJS?

NestJS é uma estrutura de aplicativo do lado do servidor para Node.js que permite criar aplicativos escaláveis ​​e eficientes. Ele é escrito em TypeScript e construído com Express.js, uma estrutura leve que é fantástica por si só, mas carece de estrutura.

O Nest tem suporte para programação orientada a objetos, programação funcional e programação reativa funcional. Esse trabalho de estrutura é uma ótima opção se você deseja muita estrutura no back-end do seu aplicativo.

O Nest tem sintaxe e estrutura semelhantes ao Angular, um framework de front-end. Ele também emprega TypeScript, serviços e injeção de dependência, assim como o Angular. Nest usa módulos e controladores e permite que você use a interface de linha de comando para criar controladores para um arquivo.

Começando

Para configurar o projeto, primeiro você precisa instalar a Nest CLI globalmente com o seguinte comando:

npm i -g @nestjs/cli

Quando a instalação estiver concluída, crie um novo projeto, assim:

nest new auth-with-nest

Em seguida, você será solicitado a escolher um gerenciador de pacotes para instalar as dependências. Para esta demonstração, usaremos o Yarn.

Fio Terminal

Escolha yarne pressione a tecla Enter . Agora, espere enquanto o Yarn instala todas as dependências necessárias para executar o aplicativo.

Configurando o banco de dados MongoDB

Para configurar e conectar seu banco de dados, instale o pacote Mongoose, bcrypt e o wrapper NestJS com o seguinte comando:

npm install --save @nestjs/mongoose @types/bcrypt mongoose bcrypt

Agora, atualize o app.module.tsarquivo e configure o Mongoose, assim:

import { MongooseModule } from '@nestjs/mongoose';
@Module({
  imports: [MongooseModule.forRoot('mongodb://localhost/authentication')],
})

No snippet acima, importamos o MongooseModulearquivo root AppModule.

Criando o módulo de usuário

Para manter seu código limpo e bem organizado, crie um módulo especificamente para usuários NestJS CLI executando o seguinte comando:

nest g module users

O código acima cria uma pasta de usuário com um users.module.tsarquivo e um app.module.tsarquivo de atualizações.

Criando o esquema do usuário

Para criar um esquema de usuário, crie um users.model.tsarquivo na src/userspasta e adicione o seguinte código:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
  @Prop()
  username: string;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);

Aqui, definimos a forma do nosso Useresquema com o @Schema()decorador e o @Prop()decorador.

O Mongoose mapeará o esquema para uma coleção do MongoDB. O esquema define a forma dos documentos da coleção.

Agora, substitua o código no user/user.module.tsarquivo e userSchemadisponibilize nas importações com o seguinte código:

import { Module } from '@nestjs/common';
import { UsersService } from './user.service';
import { UsersController } from './user.controller';
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "./user.model"

@Module({
  imports: [MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [UsersService],
  controllers: [UsersController]
})
export class UserModule {}

Criando o serviço de usuário

Com o esquema de usuário criado, execute o comando abaixo para criar um serviço de usuário:

nest g service users

Esse código cria um users.service.tsarquivo e atualiza o app.module.tsarquivo.

NB, você pode optar por criar seus arquivos e pastas manualmente, mas o NestJS CLI facilitará sua vida atualizando automaticamente as pastas necessárias

Agora, adicione o seguinte código ao users.service.tsarquivo:

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './users.model';

@Injectable()
export class UsersService {
    constructor(@InjectModel('user') private readonly userModel: Model<UserDocument>) { }
    async createUser(username: string, password: string): Promise<User> {
        return this.userModel.create({
            username,
            password,
        });
    }
    async getUser(query: object ): Promise<User> {
        return this.userModel.findOne(query);
    }
}

Aqui, usamos o @InjectModel()decorador para injetar o userModelarquivo UsersService.

Criando o controlador de usuário

Agora vamos criar um controlador de usuário para definir as rotas da API:

nest g service users

Adicione o código ao users.controller.tsarquivo:

import { Body, Controller, Post, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './users.model';
import * as bcrypt from 'bcrypt';

@Controller('auth')
export class UsersController {
    constructor(private readonly usersService: UsersService) { }

    @Post('/signup')
    async createUser(
        @Body('password') password: string,
        @Body('username') username: string,
    ): Promise<User> {
        const saltOrRounds = 10;
        const hashedPassword = await bcrypt.hash(password, saltOrRounds);
        const result = await this.usersService.createUser(
            username,
            hashedPassword,
        );
        return result;
    }
}

Aqui, definimos duas rotas de API e consumimos os serviços que criamos. Costumávamos bcryptfazer o hash da senha do usuário .

Criando o módulo de autenticação

Vamos começar criando um módulo de autenticação, assim:

nest g module auth

Este comando irá criar uma nova pasta, auth, com um auth.module.tsarquivo; ele também atualizará o app.module.tsarquivo.

Configurando o JWT

Agora, vamos implementar um token da Web JSON para autenticar usuários no aplicativo.

Para começar, instale as seguintes dependências:

npm install --save @nestjs/jwt passport-jwt
npm install --save-dev @types/passport-jwt

Em seguida, crie um novo arquivo, local.auth.tse adicione o seguinte código:

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

Aqui, implementamos uma estratégia local de passaporte para autenticar o token da Web JSON. Por padrão, a estratégia local do passaporte espera usernamee passwordpropriedades no corpo da solicitação.

Também implementamos o validate()método que o middleware do Passport chamará para verificar o usuário usando um conjunto de parâmetros específico de estratégia apropriado.

Em seguida, substitua o código no AuthModulepelo seguinte:

import { Module } from "@nestjs/common"
import { UserModule } from "src/user/user.module";
import { AuthService } from "./auth.service"
import { PassportModule } from "@nestjs/passport"
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller';
import { UsersService } from "src/user/user.service";
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "../user/user.model"
import { LocalStrategy } from './local-strategy';


@Module({
  imports: [UserModule, PassportModule, JwtModule.register({
    secret: 'secretKey',
    signOptions: { expiresIn: '60s' },
  }), MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [AuthService, UsersService, LocalStrategy],
  controllers: [AuthController],
})
export class AuthModule { }

Aqui, importamos o PassportModulee JwtModulepara a matriz de importações. Em seguida, usamos o registermétodo para registrar o JWT, fornecendo o segredo e o tempo de expiração.

Também disponibilizamos o the UserSchemanas importações e adicionamos o UserServicee o nosso LocalStrategyao leque de fornecedores.

NB, por motivos de segurança, sempre salve seu segredo JWT em uma variável de ambiente

Criando o serviço de autenticação e o controlador

Agora, vamos adicionar recursos de autenticação ao aplicativo.

Com o JWT e o Passport configurados, execute o seguinte comando para criar auth.service.tse auth.controller.tsarquivos na authpasta.:

nest generate service auth
nest generate controller auth

Em seguida, abra o auth/auth.service.tsarquivo e autentique os usuários com o seguinte código:

import { Injectable, NotAcceptableException } from '@nestjs/common';
import { UsersService } from 'src/user/user.service';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
    constructor(private readonly usersService: UsersService, private jwtService: JwtService) { }
    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.getUser({ username });
        if (!user) return null;
        const passwordValid = await bcrypt.compare(password, user.password)
        if (!user) {
            throw new NotAcceptableException('could not find the user');
        }
        if (user && passwordValid) {
            return user;
        }
        return null;
    }
    async login(user: any) {
        const payload = { username: user.username, sub: user._id };
        return {
            access_token: this.jwtService.sign(payload),
        };
    }
}

Aqui, criamos o validateUsermétodo para verificar se um usuário do user.modelbanco de dados corresponde a um registro de usuário do banco de dados. Se não houver correspondência, o método retornará um nullvalor.

Também criamos o loginmétodo que usa o jwtService.signmétodo para gerar um token de acesso JWT para o usuário retornado validatedo nosso arquivo LocalStrategy.

Agora, adicione o trecho de código abaixo ao auth/auth.controller.tsarquivo para criar uma rota para o usuário login.

import { Controller, Request, Post, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthGuard } from '@nestjs/passport';

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

    @UseGuards(AuthGuard('local'))
    @Post('auth/login')
    async login(@Request() req) {
        return this.authService.login(req.user);
    }
}

Aqui, usamos o @UseGuards()decorador para impor a autenticação quando um usuário solicita a rota de login. Com a AuthGuardclasse, podemos autenticar um usuário usando a localestratégia.

Testando o aplicativo

Agora vamos testar o aplicativo usando o Postman. Começaremos com o signup route.

Primeiro, inicie o aplicativo:

npm run start

Em seguida, abra o Postman e teste a rota de inscrição enviando uma solicitação de postagem para o endpoint. localhost:3000/users/signup.

Rota de inscrição do carteiro

Agora, teste o endpoint de login enviando uma solicitação de postagem para o endpoint. localhost:3000/auth/login.

Ponto de extremidade pós-solicitação

Se o usernamee passwordexistir no banco de dados, o usuário receberá um access_tokenconforme mostrado acima. Com o access_token, o usuário poderá acessar as rotas protegidas na API.

Conclusão

Neste tutorial, fornecemos uma visão geral do NestJS e demonstramos como implementar a autenticação de usuário JWT em uma API NestJS.

Agora que você tem esse conhecimento, como lidará com a autenticação do usuário em seu próximo projeto Nest? Para saber mais sobre a autenticação NestJS JWT, consulte a documentação oficial .

Fonte: https://blog.logrocket.com/how-to-implement-jwt-authentication-nestjs/

#nestjs #jwt #authentic 

Como Implementar A Autenticação JWT No NestJS
Duong Tran

Duong Tran

1660407267

Cách Triển Khai Xác Thực JWT Trong NestJS

Xác thực là một trong những khía cạnh quan trọng nhất của bất kỳ ứng dụng nào. Nó cải thiện tính bảo mật của ứng dụng bằng cách xác minh người dùng trước khi cấp cho họ quyền truy cập vào các phần khác nhau của ứng dụng. Xác thực cũng cho phép các công ty theo dõi có bao nhiêu người đang sử dụng sản phẩm của họ.

Điều tối quan trọng là phải định cấu hình xác thực chính xác. Trên thực tế, Dự án Bảo mật Ứng dụng Web Mở (OWASP)  xác định các lỗi nhận dạng và xác thực trong danh sách mười rủi ro bảo mật ứng dụng web hàng đầu.

Hướng dẫn này sẽ trình bày quy trình từng bước để triển khai xác thực người dùng JWT trong NestJS.

Điều kiện tiên quyết

Hướng dẫn này là một minh chứng thực hành. Để làm theo, hãy đảm bảo bạn đã cài đặt những thứ sau:

  • Node.js v14 trở lên
  • MongoDB
  • Sợi được cài đặt trên toàn cầu; sử dụng lệnhnpm install --global yarn

NestJS là gì?

NestJS là một khung ứng dụng phía máy chủ cho Node.js cho phép bạn tạo các ứng dụng có thể mở rộng và hiệu quả. Nó được viết bằng TypeScript và được xây dựng bằng Express.js, một khung công tác nhẹ, tự nó tuyệt vời nhưng thiếu cấu trúc.

Nest hỗ trợ lập trình hướng đối tượng, lập trình chức năng và lập trình phản ứng chức năng. Công việc khung này là một lựa chọn tuyệt vời nếu bạn muốn có nhiều cấu trúc trên phần phụ trợ của ứng dụng của mình.

Nest có cú pháp và cấu trúc tương tự như Angular, một khuôn khổ giao diện người dùng. Nó cũng sử dụng TypeScript, dịch vụ và chèn phụ thuộc, giống như Angular. Nest sử dụng các mô-đun và bộ điều khiển, đồng thời cho phép bạn sử dụng giao diện dòng lệnh để tạo bộ điều khiển cho một tệp.

Bắt đầu

Để thiết lập dự án, trước tiên bạn cần cài đặt Nest CLI trên toàn cầu bằng lệnh sau:

npm i -g @nestjs/cli

Khi quá trình cài đặt hoàn tất, hãy tạo một dự án mới, như sau:

nest new auth-with-nest

Tiếp theo, bạn sẽ được nhắc chọn một trình quản lý gói để cài đặt các phần phụ thuộc. Đối với phần trình diễn này, chúng tôi sẽ sử dụng Yarn.

Sợi đầu cuối

Chọn yarnvà nhấn phím Enter . Bây giờ, hãy đợi trong khi Yarn cài đặt tất cả các phụ thuộc bắt buộc cần thiết để chạy ứng dụng.

Thiết lập cơ sở dữ liệu MongoDB

Để thiết lập và kết nối cơ sở dữ liệu của bạn, hãy cài đặt gói Mongoose, bcrypt và trình bao bọc NestJS bằng lệnh sau:

npm install --save @nestjs/mongoose @types/bcrypt mongoose bcrypt

Bây giờ, hãy cập nhật app.module.tstệp và thiết lập Mongoose, như sau:

import { MongooseModule } from '@nestjs/mongoose';
@Module({
  imports: [MongooseModule.forRoot('mongodb://localhost/authentication')],
})

Trong đoạn mã trên, chúng tôi đã nhập mã MongooseModulevào thư mục gốc AppModule.

Tạo mô-đun người dùng

Để giữ cho mã của bạn sạch sẽ và được tổ chức tốt, hãy tạo một mô-đun dành riêng cho người dùng NestJS CLI bằng cách chạy lệnh sau:

nest g module users

Đoạn mã trên tạo một thư mục người dùng có users.module.tstệp và app.module.tstệp cập nhật.

Tạo lược đồ người dùng

Để tạo một lược đồ người dùng, hãy tạo một users.model.tstệp trong src/usersthư mục và thêm mã sau:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
  @Prop()
  username: string;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);

Ở đây, chúng tôi đã xác định hình dạng của Userlược đồ của chúng tôi với trình @Schema()trang trí và trình @Prop()trang trí.

Mongoose sẽ ánh xạ lược đồ tới một bộ sưu tập MongoDB. Lược đồ xác định hình dạng của các tài liệu của bộ sưu tập.

Bây giờ, hãy thay thế mã trong user/user.module.tstệp và cung cấp mã userSchemacó sẵn trong nhập bằng mã sau:

import { Module } from '@nestjs/common';
import { UsersService } from './user.service';
import { UsersController } from './user.controller';
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "./user.model"

@Module({
  imports: [MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [UsersService],
  controllers: [UsersController]
})
export class UserModule {}

Tạo dịch vụ người dùng

Với lược đồ người dùng được tạo, hãy chạy lệnh dưới đây để tạo dịch vụ người dùng:

nest g service users

Mã này tạo một users.service.tstệp và cập nhật app.module.tstệp.

Không, bạn có thể chọn tạo các tệp và thư mục của mình theo cách thủ công, nhưng NestJS CLI sẽ giúp cuộc sống của bạn dễ dàng hơn bằng cách tự động cập nhật các thư mục cần thiết

Bây giờ, hãy thêm mã sau vào users.service.tstệp:

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './users.model';

@Injectable()
export class UsersService {
    constructor(@InjectModel('user') private readonly userModel: Model<UserDocument>) { }
    async createUser(username: string, password: string): Promise<User> {
        return this.userModel.create({
            username,
            password,
        });
    }
    async getUser(query: object ): Promise<User> {
        return this.userModel.findOne(query);
    }
}

Ở đây, chúng tôi đã sử dụng trình @InjectModel()trang trí để đưa userModelvào UsersService.

Tạo bộ điều khiển người dùng

Bây giờ, hãy tạo bộ điều khiển người dùng để xác định các tuyến API:

nest g service users

Thêm mã vào users.controller.tstệp:

import { Body, Controller, Post, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './users.model';
import * as bcrypt from 'bcrypt';

@Controller('auth')
export class UsersController {
    constructor(private readonly usersService: UsersService) { }

    @Post('/signup')
    async createUser(
        @Body('password') password: string,
        @Body('username') username: string,
    ): Promise<User> {
        const saltOrRounds = 10;
        const hashedPassword = await bcrypt.hash(password, saltOrRounds);
        const result = await this.usersService.createUser(
            username,
            hashedPassword,
        );
        return result;
    }
}

Ở đây, chúng tôi đã xác định hai tuyến API và sử dụng các dịch vụ mà chúng tôi đã tạo. Chúng tôi đã sử dụng bcryptđể băm mật khẩu người dùng .

Tạo mô-đun xác thực

Hãy bắt đầu bằng cách tạo một mô-đun auth, như sau:

nest g module auth

Lệnh này sẽ tạo một thư mục mới auth, với một auth.module.tstệp; nó cũng sẽ cập nhật app.module.tstệp.

Định cấu hình JWT

Bây giờ, hãy triển khai mã thông báo web JSON để xác thực người dùng vào ứng dụng.

Để bắt đầu, hãy cài đặt các phần phụ thuộc sau:

npm install --save @nestjs/jwt passport-jwt
npm install --save-dev @types/passport-jwt

Tiếp theo, tạo một tệp mới local.auth.tsvà thêm mã sau:

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

Tại đây, chúng tôi đã triển khai chiến lược địa phương hộ chiếu để xác thực mã thông báo web JSON. Theo mặc định, chiến lược địa phương hộ chiếu mong đợi usernamepasswordthuộc tính trong phần thân yêu cầu.

Chúng tôi cũng triển khai validate()phương pháp mà phần mềm trung gian của Passport sẽ gọi để xác minh người dùng bằng cách sử dụng một bộ thông số phù hợp theo chiến lược cụ thể.

Tiếp theo, thay thế mã trong mã bằng mã AuthModulesau:

import { Module } from "@nestjs/common"
import { UserModule } from "src/user/user.module";
import { AuthService } from "./auth.service"
import { PassportModule } from "@nestjs/passport"
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller';
import { UsersService } from "src/user/user.service";
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "../user/user.model"
import { LocalStrategy } from './local-strategy';


@Module({
  imports: [UserModule, PassportModule, JwtModule.register({
    secret: 'secretKey',
    signOptions: { expiresIn: '60s' },
  }), MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [AuthService, UsersService, LocalStrategy],
  controllers: [AuthController],
})
export class AuthModule { }

Ở đây, chúng tôi đã nhập PassportModuleJwtModulevào mảng nhập khẩu. Sau đó, chúng tôi sử dụng registerphương pháp để đăng ký JWT, cung cấp bí mật và thời gian hết hạn.

Chúng tôi cũng đã UserSchemacung cấp sẵn hàng nhập khẩu và thêm của UserServicevà của chúng tôi LocalStrategyvào mảng các nhà cung cấp.

NB, vì lý do bảo mật, luôn lưu bí mật JWT của bạn trong một biến môi trường

Tạo dịch vụ xác thực và bộ điều khiển

Bây giờ, chúng ta hãy thêm các tính năng xác thực vào ứng dụng.

Với JWT và Passport được định cấu hình, hãy chạy lệnh sau để tạo auth.service.tsauth.controller.tscác tệp trong auththư mục:

nest generate service auth
nest generate controller auth

Tiếp theo, mở auth/auth.service.tstệp và xác thực người dùng bằng mã sau:

import { Injectable, NotAcceptableException } from '@nestjs/common';
import { UsersService } from 'src/user/user.service';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
    constructor(private readonly usersService: UsersService, private jwtService: JwtService) { }
    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.getUser({ username });
        if (!user) return null;
        const passwordValid = await bcrypt.compare(password, user.password)
        if (!user) {
            throw new NotAcceptableException('could not find the user');
        }
        if (user && passwordValid) {
            return user;
        }
        return null;
    }
    async login(user: any) {
        const payload = { username: user.username, sub: user._id };
        return {
            access_token: this.jwtService.sign(payload),
        };
    }
}

Ở đây, chúng tôi đã tạo validateUserphương pháp để kiểm tra xem người dùng từ các đối tượng user.modelcó khớp với bản ghi người dùng từ cơ sở dữ liệu hay không. Nếu không có kết quả phù hợp, phương thức trả về một nullgiá trị.

Chúng tôi cũng đã tạo loginphương thức sử dụng jwtService.signphương thức này để tạo mã thông báo truy cập JWT cho người dùng trả về validatetừ của chúng tôi LocalStrategy.

Bây giờ, hãy thêm đoạn mã bên dưới vào auth/auth.controller.tstệp để tạo tuyến đường cho người dùng login.

import { Controller, Request, Post, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthGuard } from '@nestjs/passport';

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

    @UseGuards(AuthGuard('local'))
    @Post('auth/login')
    async login(@Request() req) {
        return this.authService.login(req.user);
    }
}

Ở đây, chúng tôi đã sử dụng trình @UseGuards()trang trí để thực thi xác thực khi người dùng yêu cầu lộ trình đăng nhập. Với AuthGuardlớp, chúng tôi có thể xác thực người dùng bằng cách sử dụng localchiến lược.

Kiểm tra ứng dụng

Bây giờ chúng ta hãy thử nghiệm ứng dụng bằng Postman. Chúng tôi sẽ bắt đầu với signup route.

Đầu tiên, khởi động ứng dụng:

npm run start

Tiếp theo, mở Postman và kiểm tra lộ trình đăng ký bằng cách gửi yêu cầu đăng đến điểm cuối. localhost:3000/users/signup.

Lộ trình Đăng ký Người đưa thư

Bây giờ, hãy kiểm tra điểm cuối đăng nhập bằng cách gửi một yêu cầu đăng đến điểm cuối. localhost:3000/auth/login.

Đăng điểm cuối yêu cầu

Nếu usernamepasswordtồn tại trong cơ sở dữ liệu, người dùng sẽ nhận được một access_tokennhư hình trên. Với access_token, người dùng sẽ có thể truy cập các tuyến được bảo vệ trong API.

Sự kết luận

Trong hướng dẫn này, chúng tôi đã cung cấp tổng quan về NestJS và sau đó trình bày cách triển khai xác thực người dùng JWT trên API NestJS.

Bây giờ bạn đã có kiến ​​thức này, bạn sẽ xử lý xác thực người dùng trong dự án Nest tiếp theo của mình như thế nào? Để tìm hiểu thêm về xác thực NestJS JWT, hãy tham khảo tài liệu chính thức .

Nguồn: https://blog.logrocket.com/how-to-implement-jwt-authentication-nestjs/

 #nestjs #jwt #authentic 

Cách Triển Khai Xác Thực JWT Trong NestJS
伊藤  直子

伊藤 直子

1660404600

NestJS で JWT 認証を実装する方法

認証は、アプリケーションの最も重要な側面の 1 つです。アプリケーションのさまざまな部分へのアクセスを許可する前にユーザーを検証することで、アプリのセキュリティを向上させます。認証により、企業は製品を使用している人数を追跡することもできます。

認証を正しく構成することは非常に重要です。実際、Open Web Application Security Project (OWASP) は、Web アプリケーションのセキュリティ リスクのトップ 10 のリストで識別と認証の失敗を特定しています。

このチュートリアルでは、NestJS で JWT ユーザー認証を実装するための段階的なプロセスを示します。

前提条件

このチュートリアルは実践的なデモンストレーションです。先に進むには、以下がインストールされていることを確認してください。

  • Node.js v14 以降
  • モンゴDB
  • グローバルにインストールされた糸。コマンドを使用npm install --global yarn

NestJS とは何ですか?

NestJS は、スケーラブルで効率的なアプリを作成できる Node.js 用のサーバー側アプリケーション フレームワークです。TypeScript で記述され、Express.js で構築されています。Express.js は、それ自体は優れていますが、構造に欠ける軽量フレームワークです。

Nest は、オブジェクト指向プログラミング、関数型プログラミング、関数型リアクティブ プログラミングをサポートしています。このフレームワークは、アプリのバックエンドに多くの構造が必要な場合に最適です。

Nest は、フロントエンド フレームワークである Angular と同様の構文と構造を持っています。また、Angular と同様に、TypeScript、サービス、依存性注入も採用しています。Nest はモジュールとコントローラーを使用し、コマンドライン インターフェイスを使用してファイルのコントローラーを作成できるようにします。

入門

プロジェクトをセットアップするには、まず次のコマンドを使用して Nest CLI をグローバルにインストールする必要があります。

npm i -g @nestjs/cli

インストールが完了したら、次のように新しいプロジェクトを作成します。

nest new auth-with-nest

次に、依存関係をインストールするパッケージ マネージャーを選択するよう求められます。このデモでは、Yarn を使用します。

ターミナルヤーン

を選択yarnし、Enterキーを押します。ここで、Yarn がアプリケーションの実行に必要なすべての依存関係をインストールするまで待ちます。

MongoDB データベースのセットアップ

データベースをセットアップして接続するには、次のコマンドを使用して、Mongoose パッケージ、bcrypt、および NestJS ラッパーをインストールします。

npm install --save @nestjs/mongoose @types/bcrypt mongoose bcrypt

次に、ファイルを更新しapp.module.tsて Mongoose を次のように設定します。

import { MongooseModule } from '@nestjs/mongoose';
@Module({
  imports: [MongooseModule.forRoot('mongodb://localhost/authentication')],
})

MongooseModule上記のスニペットでは、 をrootにインポートしましたAppModule

ユーザーモジュールの作成

コードをクリーンで適切に整理するには、次のコマンドを実行して、NestJS CLI ユーザー専用のモジュールを作成します。

nest g module users

上記のコードは、users.module.tsファイルとapp.module.ts更新ファイルを含むユーザー フォルダーを作成します。

ユーザースキーマの作成

ユーザー スキーマを作成するusers.model.tsには、フォルダーにファイルを作成しsrc/users、次のコードを追加します。

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
  @Prop()
  username: string;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);

ここでは、デコレータとデコレータをUser使用してスキーマの形状を定義しました。@Schema()@Prop()

Mongoose はスキーマを MongoDB コレクションにマップします。スキーマは、コレクションのドキュメントの形状を定義します。

user/user.module.tsここで、ファイル内のコードを置き換えてuserSchema、インポートで次のコードを使用できるようにします。

import { Module } from '@nestjs/common';
import { UsersService } from './user.service';
import { UsersController } from './user.controller';
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "./user.model"

@Module({
  imports: [MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [UsersService],
  controllers: [UsersController]
})
export class UserModule {}

ユーザー サービスの作成

ユーザー スキーマを作成したら、次のコマンドを実行してユーザー サービスを作成します。

nest g service users

このコードはファイルを作成し、users.service.tsファイルを更新しapp.module.tsます。

注意: ファイルとフォルダーを手動で作成することもできますが、NestJS CLI を使用すると、必要なフォルダーが自動的に更新されるため、作業が楽になります。

users.service.tsここで、次のコードをファイルに追加します。

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './users.model';

@Injectable()
export class UsersService {
    constructor(@InjectModel('user') private readonly userModel: Model<UserDocument>) { }
    async createUser(username: string, password: string): Promise<User> {
        return this.userModel.create({
            username,
            password,
        });
    }
    async getUser(query: object ): Promise<User> {
        return this.userModel.findOne(query);
    }
}

ここでは、@InjectModel()デコレータを使用して を に注入しuserModelましたUsersService

ユーザーコントローラーの作成

それでは、API ルートを定義するユーザー コントローラーを作成しましょう。

nest g service users

users.controller.tsファイルにコードを追加します。

import { Body, Controller, Post, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './users.model';
import * as bcrypt from 'bcrypt';

@Controller('auth')
export class UsersController {
    constructor(private readonly usersService: UsersService) { }

    @Post('/signup')
    async createUser(
        @Body('password') password: string,
        @Body('username') username: string,
    ): Promise<User> {
        const saltOrRounds = 10;
        const hashedPassword = await bcrypt.hash(password, saltOrRounds);
        const result = await this.usersService.createUser(
            username,
            hashedPassword,
        );
        return result;
    }
}

ここでは、2 つの API ルートを定義し、作成したサービスを使用しました。ユーザーのパスワードbcryptをハッシュ化していました。

認証モジュールの作成

次のように、認証モジュールを作成することから始めましょう。

nest g module auth

authこのコマンドは、auth.module.tsファイルを含む新しいフォルダー を作成します。ファイルも更新されapp.module.tsます。

JWT の構成

次に、 JSON Web トークンを実装して、ユーザーをアプリケーションに認証します。

開始するには、次の依存関係をインストールします。

npm install --save @nestjs/jwt passport-jwt
npm install --save-dev @types/passport-jwt

次に、新しいファイルを作成しlocal.auth.ts、次のコードを追加します。

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

ここでは、JSON Web トークンを認証するためのパスポート ローカル戦略を実装しました。デフォルトでは、passport-local 戦略は要求本文にusernameおよびプロパティを期待します。password

validate()また、適切な戦略固有のパラメーター セットを使用してユーザーを確認するために Passport ミドルウェアが呼び出すメソッドも実装しました。

次に、 のコードを次のコードに置き換えAuthModuleます。

import { Module } from "@nestjs/common"
import { UserModule } from "src/user/user.module";
import { AuthService } from "./auth.service"
import { PassportModule } from "@nestjs/passport"
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller';
import { UsersService } from "src/user/user.service";
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "../user/user.model"
import { LocalStrategy } from './local-strategy';


@Module({
  imports: [UserModule, PassportModule, JwtModule.register({
    secret: 'secretKey',
    signOptions: { expiresIn: '60s' },
  }), MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [AuthService, UsersService, LocalStrategy],
  controllers: [AuthController],
})
export class AuthModule { }

ここでは、インポートの配列にPassportModuleandをインポートしました。JwtModule次に、registerメソッドを使用して JWT を登録し、シークレットと有効期限を提供しました。

またUserSchema、 をインポートで使用できるようにし、プロバイダーの配列にUserServiceと ourを追加しました。LocalStrategy

NB、 セキュリティ上の理由から、常に JWT シークレットを環境変数に保存してください

認証サービスとコントローラーの作成

それでは、アプリケーションに認証機能を追加しましょう。

JWT と Passport が構成されている状態で、次のコマンドを実行してフォルダーにファイルを作成auth.service.tsします。auth.controller.tsauth

nest generate service auth
nest generate controller auth

次に、auth/auth.service.tsファイルを開き、次のコードでユーザーを認証します。

import { Injectable, NotAcceptableException } from '@nestjs/common';
import { UsersService } from 'src/user/user.service';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
    constructor(private readonly usersService: UsersService, private jwtService: JwtService) { }
    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.getUser({ username });
        if (!user) return null;
        const passwordValid = await bcrypt.compare(password, user.password)
        if (!user) {
            throw new NotAcceptableException('could not find the user');
        }
        if (user && passwordValid) {
            return user;
        }
        return null;
    }
    async login(user: any) {
        const payload = { username: user.username, sub: user._id };
        return {
            access_token: this.jwtService.sign(payload),
        };
    }
}

ここでは、のユーザーがデータベースのユーザー レコードと一致するvalidateUserかどうかを確認するメソッドを作成しました。user.model一致するものがない場合、メソッドはnull値を返します。

loginメソッドを使用して、からjwtService.sign返されたユーザーの JWT アクセス トークンを生成するメソッドも作成しました。validateLocalStrategy

次に、以下のコード スニペットをauth/auth.controller.tsファイルに追加して、ユーザーのルートを作成しますlogin

import { Controller, Request, Post, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthGuard } from '@nestjs/passport';

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

    @UseGuards(AuthGuard('local'))
    @Post('auth/login')
    async login(@Request() req) {
        return this.authService.login(req.user);
    }
}

ここでは、@UseGuards()デコレータを使用して、ユーザーがログイン ルートを要求したときに認証を強制しました。クラスを使用すると、戦略AuthGuardを使用してユーザーを認証できます。local

アプリケーションのテスト

次に、Postman を使用してアプリケーションをテストしましょう。から始めましょうsignup route

まず、アプリケーションを起動します。

npm run start

次に、Postman を開き、ポスト リクエストをエンドポイントに送信してサインアップ ルートをテストします。localhost:3000/users/signup.

郵便配達員のサインアップ ルート

ここで、ポスト リクエストをエンドポイントに送信して、ログイン エンドポイントをテストします。localhost:3000/auth/login.

ポスト リクエスト エンドポイント

usernameとがデータベースに存在する場合、ユーザーは上記passwordのように を受け取ります。access_tokenを使用するaccess_tokenと、ユーザーは API で保護されたルートにアクセスできるようになります。

結論

このチュートリアルでは、NestJS の概要を説明し、JWT ユーザー認証を NestJS API に実装する方法を示しました。

この知識が得られたので、次の Nest プロジェクトでユーザー認証をどのように処理しますか? NestJS JWT 認証の詳細については、公式ドキュメントを参照してください。

ソース: https://blog.logrocket.com/how-to-implement-jwt-authentication-nestjs/

 #nestjs #jwt #authentic 

NestJS で JWT 認証を実装する方法
曾 俊

曾 俊

1660403535

如何在 NestJS 中实现 JWT 认证

身份验证是任何应用程序最重要的方面之一。它通过在授予用户访问应用程序不同部分的访问权限之前验证用户来提高应用程序的安全性。身份验证还使公司能够跟踪有多少人在使用他们的产品。

正确配置身份验证至关重要。事实上,开放 Web 应用程序安全项目 (OWASP) 在其十大 Web 应用程序安全风险列表中确定了识别和身份验证失败。

本教程将演示在 NestJS 中实现 JWT 用户身份验证的分步过程。

先决条件

本教程是一个动手演示。要继续进行,请确保您已安装以下内容:

  • Node.js v14 及以上
  • MongoDB
  • 纱线全球安装;使用命令npm install --global yarn

什么是 NestJS?

NestJS 是 Node.js 的服务器端应用程序框架,可让您创建可扩展且高效的应用程序。它是用 TypeScript 编写的,并使用 Express.js 构建,这是一个轻量级的框架,它本身就很棒,但缺乏结构。

Nest 支持面向对象编程、函数式编程和函数式反应式编程。如果你想在你的应用程序的后端有很多结构,这个框架是一个很好的选择。

Nest 的语法和结构与前端框架 Angular 相似。它还使用 TypeScript、服务和依赖注入,就像 Angular 一样。Nest 使用模块和控制器,并允许您使用命令行界面为文件创建控制器。

入门

要设置项目,您首先需要使用以下命令全局安装 Nest CLI:

npm i -g @nestjs/cli

安装完成后,创建一个新项目,如下所示:

nest new auth-with-nest

接下来,系统将提示您选择包管理器来安装依赖项。对于这个演示,我们将使用 Yarn。

终端纱

选择yarn并按Enter键。现在,等待 Yarn 安装运行应用程序所需的所有依赖项。

设置 MongoDB 数据库

要设置和连接数据库,请使用以下命令安装 Mongoose 包、bcrypt 和 NestJS 包装器:

npm install --save @nestjs/mongoose @types/bcrypt mongoose bcrypt

现在,更新app.module.ts文件并设置 Mongoose,如下所示:

import { MongooseModule } from '@nestjs/mongoose';
@Module({
  imports: [MongooseModule.forRoot('mongodb://localhost/authentication')],
})

在上面的代码片段中,我们将 导入MongooseModule到 rootAppModule中。

创建用户模块

为了让您的代码保持整洁和井井有条,请通过运行以下命令专门为 NestJS CLI 用户创建一个模块:

nest g module users

上面的代码创建了一个包含users.module.ts文件和app.module.ts更新文件的用户文件夹。

创建用户架构

要创建用户架构,users.model.ts请在文件夹中创建一个文件src/users并添加以下代码:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
  @Prop()
  username: string;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);

在这里,我们用装饰器和装饰器定义了User模式的形状。@Schema()@Prop()

Mongoose 会将模式映射到 MongoDB 集合。模式定义了集合文档的形状。

现在,替换user/user.module.ts文件中的代码并userSchema在导入中使用以下代码:

import { Module } from '@nestjs/common';
import { UsersService } from './user.service';
import { UsersController } from './user.controller';
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "./user.model"

@Module({
  imports: [MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [UsersService],
  controllers: [UsersController]
})
export class UserModule {}

创建用户服务

创建用户架构后,运行以下命令来创建用户服务:

nest g service users

此代码创建一个users.service.ts文件并更新该app.module.ts文件。

注意, 您可以选择手动创建文件和文件夹,但 NestJS CLI 会自动更新必要的文件夹,让您的生活更轻松

现在,将以下代码添加到users.service.ts文件中:

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './users.model';

@Injectable()
export class UsersService {
    constructor(@InjectModel('user') private readonly userModel: Model<UserDocument>) { }
    async createUser(username: string, password: string): Promise<User> {
        return this.userModel.create({
            username,
            password,
        });
    }
    async getUser(query: object ): Promise<User> {
        return this.userModel.findOne(query);
    }
}

在这里,我们使用@InjectModel()装饰器userModelUsersService.

创建用户控制器

现在让我们创建一个用户控制器来定义 API 路由:

nest g service users

将代码添加到users.controller.ts文件中:

import { Body, Controller, Post, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './users.model';
import * as bcrypt from 'bcrypt';

@Controller('auth')
export class UsersController {
    constructor(private readonly usersService: UsersService) { }

    @Post('/signup')
    async createUser(
        @Body('password') password: string,
        @Body('username') username: string,
    ): Promise<User> {
        const saltOrRounds = 10;
        const hashedPassword = await bcrypt.hash(password, saltOrRounds);
        const result = await this.usersService.createUser(
            username,
            hashedPassword,
        );
        return result;
    }
}

在这里,我们定义了两个 API 路由并使用了我们创建的服务。我们用来bcrypt散列用户密码

创建身份验证模块

让我们从创建一个 auth 模块开始,如下所示:

nest g module auth

此命令将创建一个auth带有auth.module.ts文件的新文件夹;它还将更新app.module.ts文件。

配置 JWT

现在,让我们实现一个JSON Web 令牌来验证用户进入应用程序。

首先,安装以下依赖项:

npm install --save @nestjs/jwt passport-jwt
npm install --save-dev @types/passport-jwt

接下来,创建一个新文件 ,local.auth.ts并添加以下代码:

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

在这里,我们实施了一个本地护照策略来验证 JSON Web 令牌。默认情况下,护照本地策略在请求正文中需要usernamepassword属性。

我们还实现了validate()Passport 中间件将调用的方法,以使用适当的特定于策略的参数集来验证用户。

接下来,将 中的代码替换为AuthModule以下内容:

import { Module } from "@nestjs/common"
import { UserModule } from "src/user/user.module";
import { AuthService } from "./auth.service"
import { PassportModule } from "@nestjs/passport"
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller';
import { UsersService } from "src/user/user.service";
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "../user/user.model"
import { LocalStrategy } from './local-strategy';


@Module({
  imports: [UserModule, PassportModule, JwtModule.register({
    secret: 'secretKey',
    signOptions: { expiresIn: '60s' },
  }), MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [AuthService, UsersService, LocalStrategy],
  controllers: [AuthController],
})
export class AuthModule { }

在这里,我们将PassportModuleandJwtModule导入到导入数组中。然后我们使用该register方法注册 JWT,提供秘密和过期时间。

我们还在UserSchema导入中提供了可用,并将 theUserService和 our添加LocalStrategy到提供程序数组中。

注意, 出于安全原因,请始终将您的 JWT 密码保存在环境变量中

创建身份验证服务和控制器

现在,让我们向应用程序添加身份验证功能。

配置 JWT 和 Passport 后,运行以下命令在文件夹中创建auth.service.tsauth.controller.ts文件auth

nest generate service auth
nest generate controller auth

接下来,打开auth/auth.service.ts文件并使用以下代码对用户进行身份验证:

import { Injectable, NotAcceptableException } from '@nestjs/common';
import { UsersService } from 'src/user/user.service';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
    constructor(private readonly usersService: UsersService, private jwtService: JwtService) { }
    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.getUser({ username });
        if (!user) return null;
        const passwordValid = await bcrypt.compare(password, user.password)
        if (!user) {
            throw new NotAcceptableException('could not find the user');
        }
        if (user && passwordValid) {
            return user;
        }
        return null;
    }
    async login(user: any) {
        const payload = { username: user.username, sub: user._id };
        return {
            access_token: this.jwtService.sign(payload),
        };
    }
}

在这里,我们创建了validateUser方法来检查来自数据库的用户是否user.model匹配来自数据库的用户记录。如果没有匹配,该方法返回一个null值。

我们还创建了一个login方法,该方法使用该jwtService.sign方法validate从我们的LocalStrategy.

现在,将下面的代码片段添加到auth/auth.controller.ts文件中以为用户创建路由login

import { Controller, Request, Post, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthGuard } from '@nestjs/passport';

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

    @UseGuards(AuthGuard('local'))
    @Post('auth/login')
    async login(@Request() req) {
        return this.authService.login(req.user);
    }
}

在这里,我们使用@UseGuards()装饰器在用户请求登录路由时强制执行身份验证。通过AuthGuard该类,我们能够使用该local策略对用户进行身份验证。

测试应用程序

现在让我们使用 Postman 测试应用程序。我们将从signup route.

首先,启动应用程序:

npm run start

接下来,打开 Postman 并通过向端点发送 post 请求来测试注册路由。localhost:3000/users/signup.

邮递员注册路线

现在,通过向端点发送发布请求来测试登录端点。localhost:3000/auth/login.

发布请求端点

如果usernamepassword存在于数据库中,用户将收到access_token如上图所示。使用access_token,用户将能够访问 API 中受保护的路由。

结论

在本教程中,我们提供了 NestJS 的概述,然后演示了如何在 NestJS API 上实现 JWT 用户身份验证。

现在您已经掌握了这些知识,您将如何在下一个 Nest 项目中处理用户身份验证?要了解更多关于 NestJS JWT 身份验证的信息,请参阅官方文档

来源:https ://blog.logrocket.com/how-to-implement-jwt-authentication-nestjs/

 #nestjs #jwt #authentic 

如何在 NestJS 中实现 JWT 认证
Léon  Peltier

Léon Peltier

1660399800

Comment Implémenter L'authentification JWT Dans NestJS

L'authentification est l'un des aspects les plus importants de toute application. Il améliore la sécurité des applications en vérifiant les utilisateurs avant de leur accorder l'accès à différentes parties de l'application. L'authentification permet également aux entreprises de savoir combien de personnes utilisent leurs produits.

Il est extrêmement important de configurer correctement l'authentification. En fait, l' Open Web Application Security Project (OWASP)  identifie les échecs d'identification et d'authentification dans sa liste des dix principaux risques de sécurité des applications Web.

Ce didacticiel présente le processus étape par étape de mise en œuvre de l'authentification utilisateur JWT dans NestJS.

Conditions préalables

Ce tutoriel est une démonstration pratique. Pour suivre, assurez-vous que les éléments suivants sont installés :

  • Node.js v14 et supérieur
  • MongoDB
  • Fil installé dans le monde ; utiliser la commandenpm install --global yarn

Qu'est-ce que Nest JS ?

NestJS est un framework d'application côté serveur pour Node.js qui vous permet de créer des applications évolutives et efficaces. Il est écrit en TypeScript et construit avec Express.js, un framework léger qui est fantastique en soi mais qui manque de structure.

Nest prend en charge la programmation orientée objet, la programmation fonctionnelle et la programmation réactive fonctionnelle. Ce cadre de travail est un excellent choix si vous voulez beaucoup de structure sur le backend de votre application.

Nest a une syntaxe et une structure similaires à Angular, un framework frontal. Il utilise également TypeScript, des services et l'injection de dépendances, tout comme Angular. Nest utilise des modules et des contrôleurs et vous permet d'utiliser l'interface de ligne de commande pour créer des contrôleurs pour un fichier.

Commencer

Pour configurer le projet, vous devez d'abord installer la CLI Nest globalement avec la commande suivante :

npm i -g @nestjs/cli

Une fois l'installation terminée, créez un nouveau projet, comme ceci :

nest new auth-with-nest

Ensuite, vous serez invité à choisir un gestionnaire de packages pour installer les dépendances. Pour cette démonstration, nous utiliserons Yarn.

Fil terminal

Choisissez yarnet appuyez sur la touche Entrée . Maintenant, attendez que Yarn installe toutes les dépendances requises pour exécuter l'application.

Configuration de la base de données MongoDB

Pour configurer et connecter votre base de données, installez le package Mongoose, bcrypt et le wrapper NestJS avec la commande suivante :

npm install --save @nestjs/mongoose @types/bcrypt mongoose bcrypt

Maintenant, mettez à jour le app.module.tsfichier et configurez Mongoose, comme ceci :

import { MongooseModule } from '@nestjs/mongoose';
@Module({
  imports: [MongooseModule.forRoot('mongodb://localhost/authentication')],
})

Dans l'extrait ci-dessus, nous avons importé le MongooseModuledans la racine AppModule.

Création du module utilisateur

Pour garder votre code propre et bien organisé, créez un module spécifiquement pour les utilisateurs de NestJS CLI en exécutant la commande suivante :

nest g module users

Le code ci-dessus crée un dossier utilisateur avec un users.module.tsfichier et un app.module.tsfichier de mises à jour.

Création du schéma utilisateur

Pour créer un schéma utilisateur, créez un users.model.tsfichier dans le src/usersdossier et ajoutez le code suivant :

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
  @Prop()
  username: string;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);

Ici, nous avons défini la forme de notre Userschéma avec le @Schema()décorateur et le @Prop()décorateur.

Mongoose mappera le schéma sur une collection MongoDB. Le schéma définit la forme des documents de la collection.

Maintenant, remplacez le code dans le user/user.module.tsfichier et rendez le userSchemadisponible dans les importations avec le code suivant :

import { Module } from '@nestjs/common';
import { UsersService } from './user.service';
import { UsersController } from './user.controller';
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "./user.model"

@Module({
  imports: [MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [UsersService],
  controllers: [UsersController]
})
export class UserModule {}

Création du service utilisateur

Une fois le schéma utilisateur créé, exécutez la commande ci-dessous pour créer un service utilisateur :

nest g service users

Ce code crée un users.service.tsfichier et met à jour le app.module.tsfichier.

NB, vous pouvez choisir de créer vos fichiers et dossiers manuellement, mais la CLI NestJS vous facilitera la vie en mettant à jour automatiquement les dossiers nécessaires

Maintenant, ajoutez le code suivant au users.service.tsfichier :

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './users.model';

@Injectable()
export class UsersService {
    constructor(@InjectModel('user') private readonly userModel: Model<UserDocument>) { }
    async createUser(username: string, password: string): Promise<User> {
        return this.userModel.create({
            username,
            password,
        });
    }
    async getUser(query: object ): Promise<User> {
        return this.userModel.findOne(query);
    }
}

Ici, nous avons utilisé le @InjectModel()décorateur pour injecter le userModeldans le UsersService.

Création du contrôleur utilisateur

Créons maintenant un contrôleur utilisateur pour définir les routes de l'API :

nest g service users

Ajoutez le code au users.controller.tsfichier :

import { Body, Controller, Post, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './users.model';
import * as bcrypt from 'bcrypt';

@Controller('auth')
export class UsersController {
    constructor(private readonly usersService: UsersService) { }

    @Post('/signup')
    async createUser(
        @Body('password') password: string,
        @Body('username') username: string,
    ): Promise<User> {
        const saltOrRounds = 10;
        const hashedPassword = await bcrypt.hash(password, saltOrRounds);
        const result = await this.usersService.createUser(
            username,
            hashedPassword,
        );
        return result;
    }
}

Ici, nous avons défini deux routes d'API et consommé les services que nous avons créés. Nous avions l'habitude bcryptde hacher le mot de passe de l'utilisateur .

Création du module d'authentification

Commençons par créer un module d'authentification, comme ceci :

nest g module auth

Cette commande créera un nouveau dossier, auth, avec un auth.module.tsfichier ; il mettra également à jour le app.module.tsfichier.

Configuration de JWT

Maintenant, implémentons un jeton Web JSON pour authentifier les utilisateurs dans l'application.

Pour commencer, installez les dépendances suivantes :

npm install --save @nestjs/jwt passport-jwt
npm install --save-dev @types/passport-jwt

Ensuite, créez un nouveau fichier, local.auth.ts, et ajoutez le code suivant :

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

Ici, nous avons implémenté une stratégie de passeport local pour authentifier le jeton Web JSON. Par défaut, la stratégie de passeport local attend usernameet passwordles propriétés dans le corps de la requête.

Nous avons également implémenté la validate()méthode que le middleware Passport appellera pour vérifier l'utilisateur à l'aide d'un ensemble de paramètres spécifiques à la stratégie.

Ensuite, remplacez le code dans le AuthModulepar ce qui suit :

import { Module } from "@nestjs/common"
import { UserModule } from "src/user/user.module";
import { AuthService } from "./auth.service"
import { PassportModule } from "@nestjs/passport"
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller';
import { UsersService } from "src/user/user.service";
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "../user/user.model"
import { LocalStrategy } from './local-strategy';


@Module({
  imports: [UserModule, PassportModule, JwtModule.register({
    secret: 'secretKey',
    signOptions: { expiresIn: '60s' },
  }), MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [AuthService, UsersService, LocalStrategy],
  controllers: [AuthController],
})
export class AuthModule { }

Ici, nous avons importé le PassportModuleet JwtModuledans le tableau des importations. Ensuite, nous avons utilisé la registerméthode pour enregistrer JWT, en fournissant le secret et l'heure d'expiration.

Nous avons également rendu le UserSchemadisponible dans les importations et ajouté le UserServiceet notre LocalStrategyà la gamme de fournisseurs.

NB, pour des raisons de sécurité, sauvegardez toujours votre secret JWT dans une variable d'environnement

Création du service d'authentification et du contrôleur

Ajoutons maintenant des fonctionnalités d'authentification à l'application.

Avec JWT et Passport configurés, exécutez la commande suivante pour créer des auth.service.tsfichiers auth.controller.tsdans le authdossier :

nest generate service auth
nest generate controller auth

Ensuite, ouvrez le auth/auth.service.tsfichier et authentifiez les utilisateurs avec le code suivant :

import { Injectable, NotAcceptableException } from '@nestjs/common';
import { UsersService } from 'src/user/user.service';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
    constructor(private readonly usersService: UsersService, private jwtService: JwtService) { }
    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.getUser({ username });
        if (!user) return null;
        const passwordValid = await bcrypt.compare(password, user.password)
        if (!user) {
            throw new NotAcceptableException('could not find the user');
        }
        if (user && passwordValid) {
            return user;
        }
        return null;
    }
    async login(user: any) {
        const payload = { username: user.username, sub: user._id };
        return {
            access_token: this.jwtService.sign(payload),
        };
    }
}

Ici, nous avons créé la validateUserméthode pour vérifier si un utilisateur de user.modelcorrespond à un enregistrement d'utilisateur de la base de données. S'il n'y a pas de correspondance, la méthode renvoie une nullvaleur.

Nous avons également créé la loginméthode qui utilise la jwtService.signméthode pour générer un jeton d'accès JWT pour l'utilisateur renvoyé à partir validatede notre LocalStrategy.

Maintenant, ajoutez l'extrait de code ci-dessous au auth/auth.controller.tsfichier pour créer un itinéraire pour l'utilisateur login.

import { Controller, Request, Post, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthGuard } from '@nestjs/passport';

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

    @UseGuards(AuthGuard('local'))
    @Post('auth/login')
    async login(@Request() req) {
        return this.authService.login(req.user);
    }
}

Ici, nous avons utilisé le @UseGuards()décorateur pour appliquer l'authentification lorsqu'un utilisateur demande la route de connexion. Avec la AuthGuardclasse, nous pouvons authentifier un utilisateur en utilisant la localstratégie.

Tester l'application

Testons maintenant l'application avec Postman. Nous allons commencer par le signup route.

Tout d'abord, lancez l'application :

npm run start

Ensuite, ouvrez Postman et testez la route d'inscription en envoyant une demande de publication au point de terminaison. localhost:3000/users/signup.

Itinéraire d'inscription du facteur

Maintenant, testez le point de terminaison de connexion en envoyant une demande de publication au point de terminaison. localhost:3000/auth/login.

Point de terminaison post-demande

Si le usernameet passwordexistent dans la base de données, l'utilisateur recevra un access_tokencomme indiqué ci-dessus. Avec le access_token, l'utilisateur pourra accéder aux routes protégées dans l'API.

Conclusion

Dans ce didacticiel, nous avons fourni un aperçu de NestJS, puis montré comment implémenter l'authentification utilisateur JWT sur une API NestJS.

Maintenant que vous avez ces connaissances, comment allez-vous gérer l'authentification des utilisateurs dans votre prochain projet Nest ? Pour en savoir plus sur l'authentification NestJS JWT, consultez la documentation officielle .

Source : https://blog.logrocket.com/how-to-implement-jwt-authentication-nestjs/

  #nestjs #jwt #authentic 

Comment Implémenter L'authentification JWT Dans NestJS
Saul  Alaniz

Saul Alaniz

1660399566

Cómo Implementar La Autenticación JWT En NestJS

La autenticación es uno de los aspectos más importantes de cualquier aplicación. Mejora la seguridad de la aplicación al verificar a los usuarios antes de otorgarles acceso a diferentes partes de la aplicación. La autenticación también permite a las empresas realizar un seguimiento de cuántas personas utilizan sus productos.

Es de vital importancia configurar la autenticación correctamente. De hecho, el Proyecto de seguridad de aplicaciones web abiertas (OWASP)  identifica fallas de identificación y autenticación en su lista de los diez principales riesgos de seguridad de aplicaciones web.

Este tutorial demostrará el proceso paso a paso para implementar la autenticación de usuario JWT en NestJS.

requisitos previos

Este tutorial es una demostración práctica. Para seguir, asegúrese de tener instalado lo siguiente:

  • Node.js v14 y superior
  • MongoDB
  • Hilo instalado globalmente; usar comandonpm install --global yarn

¿Qué es NestJS?

NestJS es un marco de aplicación del lado del servidor para Node.js que le permite crear aplicaciones escalables y eficientes. Está escrito en TypeScript y construido con Express.js, un marco liviano que es fantástico por sí solo pero carece de estructura.

Nest tiene soporte para programación orientada a objetos, programación funcional y programación reactiva funcional. Este marco de trabajo es una excelente opción si desea mucha estructura en el backend de su aplicación.

Nest tiene una sintaxis y una estructura similares a las de Angular, un framework frontend. También emplea TypeScript, servicios e inyección de dependencia, al igual que Angular. Nest usa módulos y controladores y le permite usar la interfaz de línea de comandos para crear controladores para un archivo.

Empezando

Para configurar el proyecto, primero deberá instalar Nest CLI globalmente con el siguiente comando:

npm i -g @nestjs/cli

Una vez que se complete la instalación, cree un nuevo proyecto, así:

nest new auth-with-nest

A continuación, se le pedirá que elija un administrador de paquetes para instalar las dependencias. Para esta demostración, usaremos Yarn.

hilo terminal

Elija yarny presione la tecla Enter . Ahora, espere mientras Yarn instala todas las dependencias necesarias para ejecutar la aplicación.

Configuración de la base de datos MongoDB

Para configurar y conectar su base de datos, instale el paquete Mongoose, bcrypt y el contenedor NestJS con el siguiente comando:

npm install --save @nestjs/mongoose @types/bcrypt mongoose bcrypt

Ahora, actualice el app.module.tsarchivo y configure Mongoose, así:

import { MongooseModule } from '@nestjs/mongoose';
@Module({
  imports: [MongooseModule.forRoot('mongodb://localhost/authentication')],
})

En el fragmento anterior, importamos el MongooseModuleen la raíz AppModule.

Creando el módulo de usuario

Para mantener su código limpio y bien organizado, cree un módulo específico para los usuarios de la CLI de NestJS ejecutando el siguiente comando:

nest g module users

El código anterior crea una carpeta de usuario con un users.module.tsarchivo y un app.module.tsarchivo de actualizaciones.

Crear el esquema de usuario

Para crear un esquema de usuario, cree un users.model.tsarchivo en la src/userscarpeta y agregue el siguiente código:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
  @Prop()
  username: string;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);

Aquí, hemos definido la forma de nuestro Useresquema con el @Schema()decorador y el @Prop()decorador.

Mongoose asignará el esquema a una colección MongoDB. El esquema define la forma de los documentos de la colección.

Ahora, reemplace el código en el user/user.module.tsarchivo y haga que userSchemaesté disponible en las importaciones con el siguiente código:

import { Module } from '@nestjs/common';
import { UsersService } from './user.service';
import { UsersController } from './user.controller';
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "./user.model"

@Module({
  imports: [MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [UsersService],
  controllers: [UsersController]
})
export class UserModule {}

Creando el servicio de usuario

Con el esquema de usuario creado, ejecute el siguiente comando para crear un servicio de usuario:

nest g service users

Este código crea un users.service.tsarchivo y lo actualiza app.module.ts.

NB, puede optar por crear sus archivos y carpetas manualmente, pero la CLI de NestJS le facilitará la vida al actualizar automáticamente las carpetas necesarias

Ahora, agregue el siguiente código al users.service.tsarchivo:

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './users.model';

@Injectable()
export class UsersService {
    constructor(@InjectModel('user') private readonly userModel: Model<UserDocument>) { }
    async createUser(username: string, password: string): Promise<User> {
        return this.userModel.create({
            username,
            password,
        });
    }
    async getUser(query: object ): Promise<User> {
        return this.userModel.findOne(query);
    }
}

Aquí, usamos el @InjectModel()decorador para inyectar userModelen el archivo UsersService.

Creando el controlador de usuario

Ahora vamos a crear un controlador de usuario para definir las rutas de la API:

nest g service users

Agregue el código al users.controller.tsarchivo:

import { Body, Controller, Post, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './users.model';
import * as bcrypt from 'bcrypt';

@Controller('auth')
export class UsersController {
    constructor(private readonly usersService: UsersService) { }

    @Post('/signup')
    async createUser(
        @Body('password') password: string,
        @Body('username') username: string,
    ): Promise<User> {
        const saltOrRounds = 10;
        const hashedPassword = await bcrypt.hash(password, saltOrRounds);
        const result = await this.usersService.createUser(
            username,
            hashedPassword,
        );
        return result;
    }
}

Aquí, definimos dos rutas API y consumimos los servicios que creamos. Solíamos codificar bcryptla contraseña del usuario .

Creando el módulo de autenticación

Comencemos por crear un módulo de autenticación, así:

nest g module auth

Este comando creará una nueva carpeta, auth, con un auth.module.tsarchivo; también actualizará el app.module.tsarchivo.

Configuración de JWT

Ahora, implementemos un token web JSON para autenticar a los usuarios en la aplicación.

Para comenzar, instale las siguientes dependencias:

npm install --save @nestjs/jwt passport-jwt
npm install --save-dev @types/passport-jwt

A continuación, cree un nuevo archivo, local.auth.tsy agregue el siguiente código:

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

Aquí, implementamos una estrategia de pasaporte local para autenticar el token web JSON. De forma predeterminada, la estrategia de pasaporte local espera usernamepropiedades passworden el cuerpo de la solicitud.

También implementamos el validate()método al que llamará el middleware de Passport para verificar al usuario utilizando un conjunto de parámetros específico de la estrategia adecuada.

A continuación, reemplace el código en el AuthModulecon el siguiente:

import { Module } from "@nestjs/common"
import { UserModule } from "src/user/user.module";
import { AuthService } from "./auth.service"
import { PassportModule } from "@nestjs/passport"
import { JwtModule } from '@nestjs/jwt';
import { AuthController } from './auth.controller';
import { UsersService } from "src/user/user.service";
import { MongooseModule } from "@nestjs/mongoose"
import { UserSchema } from "../user/user.model"
import { LocalStrategy } from './local-strategy';


@Module({
  imports: [UserModule, PassportModule, JwtModule.register({
    secret: 'secretKey',
    signOptions: { expiresIn: '60s' },
  }), MongooseModule.forFeature([{ name: "user", schema: UserSchema }])],
  providers: [AuthService, UsersService, LocalStrategy],
  controllers: [AuthController],
})
export class AuthModule { }

Aquí, importamos el PassportModuley JwtModuleen la matriz de importaciones. Luego usamos el registermétodo para registrar JWT, proporcionando el secreto y el tiempo de vencimiento.

También pusimos a UserSchemadisposición en las importaciones y agregamos el UserServicey nuestro LocalStrategya la variedad de proveedores.

NB, por razones de seguridad, siempre guarde su secreto JWT en una variable de entorno

Crear el servicio de autenticación y el controlador

Ahora, agreguemos funciones de autenticación a la aplicación.

Con JWT y Passport configurados, ejecute el siguiente comando para crear auth.service.tsarchivos auth.controller.tsen la authcarpeta:

nest generate service auth
nest generate controller auth

A continuación, abra el auth/auth.service.tsarchivo y autentique a los usuarios con el siguiente código:

import { Injectable, NotAcceptableException } from '@nestjs/common';
import { UsersService } from 'src/user/user.service';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
    constructor(private readonly usersService: UsersService, private jwtService: JwtService) { }
    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.getUser({ username });
        if (!user) return null;
        const passwordValid = await bcrypt.compare(password, user.password)
        if (!user) {
            throw new NotAcceptableException('could not find the user');
        }
        if (user && passwordValid) {
            return user;
        }
        return null;
    }
    async login(user: any) {
        const payload = { username: user.username, sub: user._id };
        return {
            access_token: this.jwtService.sign(payload),
        };
    }
}

Aquí, creamos el validateUsermétodo para verificar si un usuario de user.modelcoincide con un registro de usuario de la base de datos. Si no hay ninguna coincidencia, el método devuelve un nullvalor.

También creamos el loginmétodo que usa el jwtService.signmétodo para generar un token de acceso JWT para el usuario devuelto validatedesde nuestro archivo LocalStrategy.

Ahora, agregue el fragmento de código a continuación al auth/auth.controller.tsarchivo para crear una ruta para el usuario login.

import { Controller, Request, Post, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthGuard } from '@nestjs/passport';

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

    @UseGuards(AuthGuard('local'))
    @Post('auth/login')
    async login(@Request() req) {
        return this.authService.login(req.user);
    }
}

Aquí, usamos el @UseGuards()decorador para hacer cumplir la autenticación cuando un usuario solicita la ruta de inicio de sesión. Con la AuthGuardclase, podemos autenticar a un usuario usando la localestrategia.

Probando la aplicación

Ahora probemos la aplicación usando Postman. Comenzaremos con el signup route.

Primero, inicie la aplicación:

npm run start

A continuación, abra Postman y pruebe la ruta de registro enviando una solicitud de publicación al punto final. localhost:3000/users/signup.

Ruta de registro del cartero

Ahora, pruebe el punto final de inicio de sesión enviando una solicitud posterior al punto final. localhost:3000/auth/login.

Publicar punto final de solicitud

Si el usernamey passwordexiste en la base de datos, el usuario recibirá un access_tokencomo se muestra arriba. Con el access_token, el usuario podrá acceder a las rutas protegidas en la API.

Conclusión

En este tutorial, brindamos una descripción general de NestJS y luego demostramos cómo implementar la autenticación de usuario JWT en una API de NestJS.

Ahora que tiene este conocimiento, ¿cómo manejará la autenticación de usuario en su próximo proyecto de Nest? Para obtener más información sobre la autenticación JWT de NestJS, consulte la documentación oficial .

Fuente: https://blog.logrocket.com/how-to-implement-jwt-authentication-nestjs/

  #nestjs #jwt #authentic 

Cómo Implementar La Autenticación JWT En NestJS

How to Implement JWT Authentication in NestJS

Authentication is one of the most important aspects of any application. It improves app security by verifying users before granting them access to different parts of the application. Authentication also enables companies to keep track of how many people are using their products.

It’s vitally important to configure authentication correctly. In fact, the Open Web Application Security Project (OWASP) identifies identification and authentication failures in its list of top ten web application security risks.

This tutorial will demonstrate the step-by-step process for implementing JWT user authentication in NestJS.

See more at: https://blog.logrocket.com/how-to-implement-jwt-authentication-nestjs/

#nestjs #jwt #authentic 

How to Implement JWT Authentication in NestJS
Hoang  Kim

Hoang Kim

1659533643

Cách Xử Lý Tải Lên Tệp Bằng NestJS Và MySQL

Trong blog này, chúng tôi sẽ hướng dẫn bạn cách xây dựng chức năng tải tệp lên bằng NestJS và MySQL.

Giới thiệu

Nhiều nhà phát triển coi thường việc tải tệp lên. Điều này có thể là do thiếu kiến ​​thức về cách tiếp cận tốt nhất để thực hiện hoặc khó xác định cách định cấu hình ứng dụng Nest.js của họ để xử lý các tệp tải lên. Nhiều người có thể muốn lưu tệp của họ trực tiếp vào cơ sở dữ liệu MySQL hoặc lưu tên hình ảnh và lưu hình ảnh trên ổ lưu trữ: tất cả phụ thuộc vào sở thích của họ và mục tiêu họ muốn đạt được. Hướng dẫn này sẽ dạy bạn cách xây dựng chức năng tải tệp lên bằng Nestjs và MySQL.

Điều kiện tiên quyết

Trước khi bạn bắt đầu làm theo hướng dẫn này, hãy đảm bảo hệ thống của bạn đáp ứng các yêu cầu sau:

Thiết lập NestJS

Khi các yêu cầu nêu trên được đáp ứng, hãy tiến hành cài đặt Nestjs CLI và tạo một dự án mới bằng cách chạy các lệnh sau:

$ npm i -g @nestjs/cli
$ nest new file-upload

Các lệnh này sẽ cài đặt Nestjs CLI và tạo một dự án Nestjs mới với cấu trúc thư mục bên dưới.

📦file-upload
┣ 📂src
┃ ┣ 📜app.controller.spec.ts
┃ ┣ 📜app.controller.ts
┃ ┣ 📜app.module.ts
┃ ┣ 📜app.service.ts
┃ ┣ 📜image.entity.ts
┃ ┗ 📜main.ts
┣ 📂test
┃ ┣ 📜app.e2e-spec.ts
┃ ┗ 📜jest-e2e.json
┣ 📜.eslintrc.js
┣ 📜.gitignore
┣ 📜.prettierrc
┣ 📜README.md
┣ 📜nest-cli.json
┣ 📜package-lock.json
┣ 📜package.json
┣ 📜tsconfig.build.json
┗ 📜tsconfig.json

Sau khi dự án Nestjs đã được tạo, hãy chuyển sang bước tiếp theo - cài đặt các phần phụ thuộc cần thiết cho ứng dụng của bạn bằng cách chạy lệnh sau:

npm install --save @nestjs/typeorm typeorm mysql2

Trong lệnh trên, bạn đã cài đặt các mô-đun TypeORMmysql2 : chúng sẽ cho phép bạn kết nối ứng dụng của mình với cơ sở dữ liệu MySQL và thực hiện các hoạt động trên đó.

Thiết lập Cơ sở dữ liệu MySQL

Với các phần phụ thuộc đã được cài đặt ở trên, hãy tiến hành thiết lập và kết nối với cơ sở dữ liệu MySQL của bạn. Để bắt đầu, hãy thêm mã vào app.module.tstệp với đoạn mã bên dưới.

...
import { TypeOrmModule } from '@nestjs/typeorm';
import { Image } from './image.entity';

@Module({
  imports: [TypeOrmModule.forRoot({
    type: 'mysql',
    host: 'localhost',
    port: 3306,
    username: 'root',
    password: '1234',
    database: 'blog',
    entities: [Image],
    synchronize: true,
  }),
  TypeOrmModule.forFeature([Image])
  ],
  ...
})
...

Trong đoạn mã trên, chúng tôi đã nhập TypeOrmModuletừ mô-đun typeorm mà chúng tôi đã cài đặt trước đó. Chúng tôi đã sử dụng forRootphương pháp để kết nối ứng dụng với cơ sở dữ liệu MySQL và chuyển thông tin đăng nhập cơ sở dữ liệu. Một điều khác cần chỉ ra ở đây là các entitiesthuộc tính, cho phép chúng tôi chỉ định các thực thể trong mô-đun của chúng tôi và sẽ cung cấp cho chúng tôi quyền truy cập vào Imagethực thể mà bạn sẽ tạo trong thời gian ngắn: chúng tôi cũng có thuộc synchronizetính được đặt trueđể tự động di chuyển cơ sở dữ liệu.

Tạo thực thể hình ảnh

Tiếp theo, hãy tạo thực thể Image mà chúng ta đã đề cập trước đó. Để bắt đầu, hãy tạo tệp image.entity.ts trong thư mục src và thêm đoạn mã bên dưới.

import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';

@Entity()
export class Image {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @CreateDateColumn()
    dateCreated: Date;

    @UpdateDateColumn()
    dateUpdated: Date;
}

Trong đoạn mã trên, chúng tôi đã nhập các trình trang trí mà chúng tôi cần để tạo một thực thể. Sử dụng các trình trang trí này, chúng tôi đã xác định các thuộc tính của thực thể. Chúng tôi có idtrường để tạo id ngẫu nhiên cho mỗi bản ghi trong cơ sở dữ liệu bằng cách sử dụng trình @PrimaryGeneratedColumn()trang trí, nametrường để lưu trữ tên của các hình ảnh sẽ được tải lên bằng trình @Columntrang trí, trường dateCreate và dateUpdate để lưu ngày bản ghi được tạo và cập nhật bằng cách sử dụng @CreateDateColumn()@UpdateDateColumn().

Tạo dịch vụ tải lên

Với thực thể Image đã được tạo, hãy tạo một dịch vụ để thực hiện các thao tác CRUD để xử lý việc tải lên tệp. Trong app.service.tstệp, hãy thêm đoạn mã bên dưới.

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Image } from './image.entity';

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Image)
    private readonly imageRepository: Repository<Image>,
  ) {}

  async getImages(): Promise<Image[]> {
    return this.imageRepository.find();
  }

  async createImage(image: Image): Promise<Image> {
    return this.imageRepository.save(image);
  }

  async getImage(id: number): Promise<Image> {
    return this.imageRepository.findOneBy({ id });
  }

  async deleteImage(id: number): Promise<void> {
    await this.imageRepository.delete(id);
  }
}

Trong đoạn mã trên, chúng tôi đã nhập trình injectRepositorytrang trí để đưa imageRepositoryvào AppServicevà trình trang trí Repositorycung cấp cho bạn các phương pháp cần thiết để thực hiện một số thao tác trên cơ sở dữ liệu của bạn. Vì vậy, đối với createImagedịch vụ hình ảnh, chúng tôi đang lưu tên của hình ảnh được tải lên sẽ được chuyển qua bộ điều khiển.

Tạo bộ điều khiển tải lên

Bây giờ chúng ta hãy tạo bộ điều khiển để sử dụng các dịch vụ. Trong app.controller.tstệp và thêm đoạn mã bên dưới.

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Image } from './image.entity';

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Image)
    private readonly imageRepository: Repository<Image>,
  ) {}

  async getImages(): Promise<Image[]> {
    return this.imageRepository.find();
  }

  async createImage(image: Image): Promise<Image> {
    return this.imageRepository.save(image);
  }

  async getImage(id: number): Promise<Image> {
    return this.imageRepository.findOneBy({ id });
  }

  async deleteImage(id: number): Promise<void> {
    await this.imageRepository.delete(id);
  }
}

Trong đoạn mã trên, chúng tôi đã nhập một số trình trang trí như FileInterceptor, UploadedFileUseInterceptors. Trình FileInterceptor()đánh chặn đối với trình xử lý tuyến đường trích xuất tệp từ yêu cầu bằng trình @UploadedFile()trang trí. Trình FileInterceptor()trang trí được xuất từ @nestjs/platform-express​​gói. Trình @UploadedFile()trang trí được xuất từ @nestjs/common. Trình FileInterceptor()trang trí nhận hai đối số, fieldNamelà chuỗi cung cấp tên của trường từ biểu mẫu HTML chứa tệp và optionslà đối tượng tùy chọn của kiểu MulterOptions. Đây là cùng một đối tượng được sử dụng bởi phương thức khởi tạo multer.

Về createImagechức năng, chúng tôi đã sử dụng các trình trang trí nói trên để xử lý việc tải lên tệp bằng cách FileInterceptor()chuyển tên trường cho hình ảnh và chúng tôi đã sửa đổi FileInterceptor()chức năng tải hình ảnh lên đĩa bằng cách chỉ định thuộc storagetính bằng cách sử dụng diskStoragehàm có sẵn trong multer. Sau đó, chúng tôi chỉ định vị trí cho các hình ảnh và tạo tên ngẫu nhiên cho các hình ảnh. Ngoài ra, chúng tôi đã thêm một filterthuộc tính để hạn chế tải lên các định dạng hình ảnh nhất định. Bây giờ chúng ta lấy tệp được giải nén bằng cách sử dụng @UploadedFile()decorator và lấy tên và lưu nó vào cơ sở dữ liệu. Bằng cách này, chúng ta có thể sử dụng tên của từng hình ảnh để lấy hình ảnh từ vị trí lưu trữ.

Để mã trên hoạt động, bạn cần cài đặt multer bằng cách chạy lệnh bên dưới trong thiết bị đầu cuối của bạn:

npm i -D @types/multer


Sau đó, bạn cần đăng ký mô-đun multer trong mảng nhập trong app.module.tstệp:

...
import { MulterModule } from '@nestjs/platform-express';


@Module({
  ...
  MulterModule.register({
    dest: './files',
  }),],
  ...

Cấu hình trên yêu cầu multer xử lý việc tải lên tệp và vị trí để tải tệp lên. Cuối cùng nhưng không kém phần quan trọng, chúng ta nên tạo một filesthư mục trong thư mục srcđể thực sự lưu trữ các tệp.

Cung cấp Tệp

Để thực sự cung cấp hình ảnh được tải lên ứng dụng của bạn cho người dùng, bạn cần cài đặt serve-staticmô-đun bằng cách chạy lệnh bên dưới.

npm install --save @nestjs/serve-static

Sau đó, đăng ký ServeStaticModulemảng nhập trong app.module.tstệp bằng đoạn mã bên dưới.

...
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

@Module({
  ...
  ServeStaticModule.forRoot({
    rootPath: join(__dirname, '..', 'files')
  }),],
  ...


Trong đoạn mã trên, bạn đã chỉ định vị trí chứa các tệp và có thể được phân phát từ đó.

Kiểm tra API

Bây giờ, hãy mở Postman và kiểm tra ứng dụng bằng cách gửi một yêu cầu POST đến điểm cuối localhost:4000/imagesvà chuyển tải trọng trong phần thân yêu cầu dưới dạng dữ liệu biểu mẫu.

Tệp của chúng tôi

Nếu bây giờ bạn nhìn vào thư mục tệp, bạn sẽ thấy tệp bạn đã tải lên. Hãy tiếp tục: thử nghiệm và chơi xung quanh các tuyến đường khác.

Sự kết luận

Thông qua hướng dẫn này, bạn đã học cách xử lý tải lên tệp bằng NestJS và MySQL. Bạn đã học cách kết nối với cơ sở dữ liệu MySQL bằng TypeORM và bạn cũng đã tạo một thực thể và tải hình ảnh lên ứng dụng Nestjs.

Liên kết: https://arctype.com/blog/nestjs-mysql-tutorial-fileuploads/

#nestjs #node #mysql #typeorm #database 

Cách Xử Lý Tải Lên Tệp Bằng NestJS Và MySQL

Как обрабатывать загрузку файлов с помощью NestJS и MySQL

В этом блоге мы научим вас, как создать функцию загрузки файлов с помощью NestJS и MySQL.

Введение

Многие разработчики презирают загрузку файлов. Это может быть связано с отсутствием знаний о наилучшем подходе или с трудностями при определении того, как настроить приложение Nest.js для обработки загрузки файлов. Многие люди могут захотеть сохранить свои файлы непосредственно в базе данных MySQL или сохранить имена изображений и сохранить изображение на диске: все зависит от их предпочтений и целей, которых они хотят достичь. В этом руководстве вы узнаете, как создать функцию загрузки файлов с помощью Nestjs и MySQL.

Предпосылки

Прежде чем приступить к выполнению этого руководства, убедитесь, что ваша система соответствует следующим требованиям:

Настройка NestJS

Как только вышеупомянутые требования будут выполнены, перейдите к установке интерфейса командной строки Nestjs и создайте новый проект, выполнив следующие команды:

$ npm i -g @nestjs/cli
$ nest new file-upload

Эти команды установят интерфейс командной строки Nestjs и создадут новый проект Nestjs со структурой папок, указанной ниже.

📦file-upload
┣ 📂src
┃ ┣ 📜app.controller.spec.ts
┃ ┣ 📜app.controller.ts
┃ ┣ 📜app.module.ts
┃ ┣ 📜app.service.ts
┃ ┣ 📜image.entity.ts
┃ ┗ 📜main.ts
┣ 📂test
┃ ┣ 📜app.e2e-spec.ts
┃ ┗ 📜jest-e2e.json
┣ 📜.eslintrc.js
┣ 📜.gitignore
┣ 📜.prettierrc
┣ 📜README.md
┣ 📜nest-cli.json
┣ 📜package-lock.json
┣ 📜package.json
┣ 📜tsconfig.build.json
┗ 📜tsconfig.json

После создания проекта Nestjs перейдите к следующему шагу — установите необходимые зависимости для вашего приложения, выполнив следующую команду:

npm install --save @nestjs/typeorm typeorm mysql2

В приведенной выше команде вы установили модули TypeORM и mysql2 : они позволят вам подключить ваше приложение к базе данных MySQL и выполнять над ней операции.

Настройте базу данных MySQL

Установив вышеуказанные зависимости, приступайте к настройке и подключению к базе данных MySQL. Для начала добавьте код в app.module.tsфайл с приведенным ниже фрагментом кода.

...
import { TypeOrmModule } from '@nestjs/typeorm';
import { Image } from './image.entity';

@Module({
  imports: [TypeOrmModule.forRoot({
    type: 'mysql',
    host: 'localhost',
    port: 3306,
    username: 'root',
    password: '1234',
    database: 'blog',
    entities: [Image],
    synchronize: true,
  }),
  TypeOrmModule.forFeature([Image])
  ],
  ...
})
...

В приведенном выше фрагменте кода мы импортировали TypeOrmModuleиз модуля typeorm, который мы установили ранее. Мы использовали этот forRootметод для подключения приложения к базе данных MySQL и передачи учетных данных базы данных. Еще одна вещь, на которую следует обратить внимание, это entitiesсвойства, которые позволили нам указать объекты в нашем модуле и которые дадут нам доступ к Imageобъекту, который вы вскоре создадите: у нас также установлено synchronizeсвойство trueдля автоматической миграции базы данных.

Создать объект изображения

Далее давайте создадим объект Image, о котором мы упоминали ранее. Для начала создайте файл image.entity.ts в каталоге src и добавьте приведенный ниже фрагмент кода.

import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';

@Entity()
export class Image {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @CreateDateColumn()
    dateCreated: Date;

    @UpdateDateColumn()
    dateUpdated: Date;
}

В приведенном выше фрагменте кода мы импортировали декораторы, необходимые для создания объекта. С помощью этих декораторов мы определили свойства сущности. У нас есть idполе для генерации случайных идентификаторов для каждой записи в базе данных с помощью @PrimaryGeneratedColumn()декоратора, nameполе для хранения имен изображений, которые будут загружены с помощью @Columnдекоратора, поля dateCreated и dateUpdate для сохранения даты создания и обновления записи. используя @CreateDateColumn()и @UpdateDateColumn().

Создание службы загрузки

Создав объект Image, давайте создадим службу для выполнения операций CRUD для обработки загрузки файлов. В app.service.tsфайл добавьте приведенный ниже фрагмент кода.

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Image } from './image.entity';

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Image)
    private readonly imageRepository: Repository<Image>,
  ) {}

  async getImages(): Promise<Image[]> {
    return this.imageRepository.find();
  }

  async createImage(image: Image): Promise<Image> {
    return this.imageRepository.save(image);
  }

  async getImage(id: number): Promise<Image> {
    return this.imageRepository.findOneBy({ id });
  }

  async deleteImage(id: number): Promise<void> {
    await this.imageRepository.delete(id);
  }
}

В приведенном выше фрагменте кода мы импортировали injectRepositoryдекоратор для внедрения imageRepositoryв AppServiceи Repositoryкоторый предоставляет вам методы, необходимые для выполнения некоторых операций в вашей базе данных. Итак, для createImageслужбы изображений мы сохраняем имя загруженного изображения, которое будет передано через контроллер.

Создание контроллера загрузки

Теперь давайте создадим контроллеры для использования сервисов. В app.controller.tsфайл и добавьте фрагмент кода ниже.

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Image } from './image.entity';

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Image)
    private readonly imageRepository: Repository<Image>,
  ) {}

  async getImages(): Promise<Image[]> {
    return this.imageRepository.find();
  }

  async createImage(image: Image): Promise<Image> {
    return this.imageRepository.save(image);
  }

  async getImage(id: number): Promise<Image> {
    return this.imageRepository.findOneBy({ id });
  }

  async deleteImage(id: number): Promise<void> {
    await this.imageRepository.delete(id);
  }
}

В приведенном выше фрагменте кода мы импортировали пару декораторов, таких как FileInterceptor, UploadedFileи UseInterceptors. Перехватчик FileInterceptor()обработчика маршрута извлекает файл из запроса с помощью @UploadedFile()декоратора. Декоратор FileInterceptor()экспортируется из @nestjs/platform-expressпакета. Декоратор @UploadedFile()экспортируется из @nestjs/common. FileInterceptor()Декоратор принимает два аргумента : fieldNameстроку, предоставляющую имя поля из HTML-формы, содержащей файл, и optionsнеобязательный объект типа MulterOptions. Это тот же объект, который используется конструктором multer.

Что касается createImageфункции, мы использовали вышеупомянутые декораторы для обработки загрузки файла, используя FileInterceptor()передачу имени поля для изображения, и мы изменили FileInterceptor()функцию для загрузки изображения на диск, указав storageсвойство с помощью diskStorageфункции, доступной в multer. Затем мы указали расположение изображений и сгенерировали случайные имена для изображений. Кроме того, мы добавили filterсвойство для ограничения загрузки определенных форматов изображений. Теперь мы получаем файл, извлеченный с помощью @UploadedFile()декоратора, получаем имя и сохраняем его в базе данных. Таким образом, мы можем использовать имя каждого изображения, чтобы получить изображение из места хранения.

Чтобы приведенный выше код работал, вам необходимо установить multer, выполнив следующую команду в своем терминале:

npm i -D @types/multer


Затем нужно прописать модуль мультера в массиве импортов в app.module.tsфайле:

...
import { MulterModule } from '@nestjs/platform-express';


@Module({
  ...
  MulterModule.register({
    dest: './files',
  }),],
  ...

Приведенная выше конфигурация указывает multer обрабатывать загрузку файла и место для загрузки файла. И последнее, но не менее важное: мы должны создать filesпапку в srcкаталоге для фактического хранения файлов.

Обслуживание файлов

Чтобы на самом деле показывать изображения, загруженные в ваше приложение, пользователю, вам необходимо установить serve-staticмодуль, выполнив приведенную ниже команду.

npm install --save @nestjs/serve-static

Затем зарегистрируйте ServeStaticModuleв массиве импорта app.module.tsфайл с фрагментом кода ниже.

...
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

@Module({
  ...
  ServeStaticModule.forRoot({
    rootPath: join(__dirname, '..', 'files')
  }),],
  ...


В приведенном выше фрагменте кода вы указали место, где находятся файлы и откуда они могут быть отправлены.

Тестирование API

Теперь откройте Postman и протестируйте приложение, отправив POST-запрос на конечную точку localhost:4000/images, и передайте полезную нагрузку в теле запроса в виде данных формы.

Наш файл

Если вы сейчас посмотрите на папку с файлами, вы должны увидеть файл, который вы загрузили. Не стесняйтесь идти вперед: тестируйте и экспериментируйте с другими маршрутами.

Вывод

Из этого руководства вы узнали, как обрабатывать загрузку файлов с помощью NestJS и MySQL. Вы узнали, как подключиться к базе данных MySQL с помощью TypeORM, а также создали объект и загрузили изображения в приложение Nestjs.

Ссылка: https://arctype.com/blog/nestjs-mysql-tutorial-fileuploads/

#nestjs #node  #mysql #typeorm #database 

Как обрабатывать загрузку файлов с помощью NestJS и MySQL
田辺  亮介

田辺 亮介

1659511980

如何使用 NestJS 和 MySQL 處理文件上傳

在這篇博客中,我們將教你如何使用 NestJS 和 MySQL 構建文件上傳功能。

介紹

許多開發人員鄙視處理文件上傳。這可以歸因於缺乏對最佳方法的了解,或者難以確定如何配置他們的 Nest.js 應用程序來處理文件上傳。許多人可能希望將他們的文件直接保存到 MySQL 數據庫,或者保存圖像名稱並將圖像保存在磁盤存儲中:這完全取決於他們的偏好和他們想要實現的目標。本教程將教您如何使用 Nestjs 和 MySQL 構建文件上傳功能。

先決條件

在開始學習本教程之前,請確保您的系統滿足以下要求:

設置 NestJS

滿足上述要求後,繼續安裝 Nestjs CLI 並通過運行以下命令創建一個新項目:

$ npm i -g @nestjs/cli
$ nest new file-upload

這些命令將安裝 Nestjs CLI 並使用以下文件夾結構創建一個新的 Nestjs 項目。

📦file-upload
┣ 📂src
┃ ┣ 📜app.controller.spec.ts
┃ ┣ 📜app.controller.ts
┃ ┣ 📜app.module.ts
┃ ┣ 📜app.service.ts
┃ ┣ 📜image.entity.ts
┃ ┗ 📜main.ts
┣ 📂test
┃ ┣ 📜app.e2e-spec.ts
┃ ┗ 📜jest-e2e.json
┣ 📜.eslintrc.js
┣ 📜.gitignore
┣ 📜.prettierrc
┣ 📜README.md
┣ 📜nest-cli.json
┣ 📜package-lock.json
┣ 📜package.json
┣ 📜tsconfig.build.json
┗ 📜tsconfig.json

創建 Nestjs 項目後,繼續下一步 - 通過運行以下命令為您的應用程序安裝所需的依賴項:

npm install --save @nestjs/typeorm typeorm mysql2

在上面的命令中,您已經安裝了TypeORMmysql2模塊:它們將使您能夠將應用程序連接到 MySQL 數據庫並對其執行操作。

設置 MySQL 數據庫

安裝上述依賴項後,繼續設置並連接到您的 MySQL 數據庫。要開始使用,請在app.module.ts文件中添加代碼以及下面的代碼片段。

...
import { TypeOrmModule } from '@nestjs/typeorm';
import { Image } from './image.entity';

@Module({
  imports: [TypeOrmModule.forRoot({
    type: 'mysql',
    host: 'localhost',
    port: 3306,
    username: 'root',
    password: '1234',
    database: 'blog',
    entities: [Image],
    synchronize: true,
  }),
  TypeOrmModule.forFeature([Image])
  ],
  ...
})
...

在上面的代碼片段中,我們TypeOrmModule從之前安裝的 typeorm 模塊導入。我們使用該forRoot方法將應用程序連接到 MySQL 數據庫並傳入數據庫憑據。這裡要指出的另一件事是entities屬性,它允許我們指定模塊中的實體,並允許我們訪問Image您將很快創建的實體:我們還將synchronize屬性設置true為自動遷移數據庫。

創建圖像實體

接下來,讓我們創建我們之前提到的 Image 實體。首先,在 src 目錄中創建一個 image.entity.ts 文件並添加下面的代碼片段。

import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';

@Entity()
export class Image {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @CreateDateColumn()
    dateCreated: Date;

    @UpdateDateColumn()
    dateUpdated: Date;
}

在上面的代碼片段中,我們導入了創建實體所需的裝飾器。使用這些裝飾器,我們定義了實體的屬性。我們有使用裝飾器id為數據庫中的每條記錄生成隨機 id 的字段,用於存儲將使用裝飾器上傳的圖像名稱的字段,用於保存記錄創建和更新日期的 dateCreated 和 dateUpdate 字段使用和。@PrimaryGeneratedColumn()name@Column@CreateDateColumn()@UpdateDateColumn()

創建上傳服務

創建 Image 實體後,讓我們創建一個服務來執行 CRUD 操作來處理文件上傳。在app.service.ts文件中,添加下面的代碼片段。

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Image } from './image.entity';

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Image)
    private readonly imageRepository: Repository<Image>,
  ) {}

  async getImages(): Promise<Image[]> {
    return this.imageRepository.find();
  }

  async createImage(image: Image): Promise<Image> {
    return this.imageRepository.save(image);
  }

  async getImage(id: number): Promise<Image> {
    return this.imageRepository.findOneBy({ id });
  }

  async deleteImage(id: number): Promise<void> {
    await this.imageRepository.delete(id);
  }
}

在上面的代碼片段中,我們已經導入了injectRepository裝飾器來注入,imageRepositoryAppServiceRepository您提供了對數據庫執行某些操作所需的方法。因此,對於createImage圖像服務,我們保存了上傳的圖像的名稱,該名稱將通過控制器傳遞。

創建上傳控制器

現在讓我們創建控制器以使用服務。在app.controller.ts文件中並添加下面的代碼片段。

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Image } from './image.entity';

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Image)
    private readonly imageRepository: Repository<Image>,
  ) {}

  async getImages(): Promise<Image[]> {
    return this.imageRepository.find();
  }

  async createImage(image: Image): Promise<Image> {
    return this.imageRepository.save(image);
  }

  async getImage(id: number): Promise<Image> {
    return this.imageRepository.findOneBy({ id });
  }

  async deleteImage(id: number): Promise<void> {
    await this.imageRepository.delete(id);
  }
}

在上面的代碼片段中,我們導入了幾個裝飾器,如FileInterceptorUploadedFileUseInterceptors。路由處理程序的攔截器使用裝飾器FileInterceptor()從請求中提取文件。裝飾器是從包中導出的@UploadedFile()。裝飾器是從. 裝飾器有兩個參數,一個是提供包含文件的 HTML 表單中的字段名稱的字符串,另一個是 MulterOptions 類型的可選對象。這與 multer 構造函數使用的對象相同。FileInterceptor()@nestjs/platform-express@UploadedFile()@nestjs/commonFileInterceptor()fieldNameoptions

關於createImage函數,我們使用上述裝飾器FileInterceptor()通過傳遞圖像的字段名稱來處理文件上傳,並且我們修改了函數以通過使用中可用的函數指定屬性來FileInterceptor()將圖像上傳到磁盤。然後我們指定圖像的位置並為圖像生成隨機名稱。此外,我們添加了一個屬性來限制某些圖像格式的上傳。現在我們使用裝飾器提取文件並獲取名稱並將其保存到數據庫中。這樣我們就可以使用每個圖像的名稱從存儲位置獲取圖像。storagediskStoragemulterfilter@UploadedFile()

要使上述代碼正常工作,您需要通過在終端中運行以下命令來安裝 multer:

npm i -D @types/multer


然後,您需要在app.module.ts文件的導入數組中註冊 multer 模塊:

...
import { MulterModule } from '@nestjs/platform-express';


@Module({
  ...
  MulterModule.register({
    dest: './files',
  }),],
  ...

上面的配置告訴 multer 處理文件上傳和上傳文件的位置。最後但同樣重要的是,我們應該files在目錄中創建一個文件夾src來實際存儲文件。

服務文件

要將應用程序上上傳的圖像實際提供給用戶,您需要serve-static通過運行以下命令來安裝模塊。

npm install --save @nestjs/serve-static

然後,使用下面的代碼片段ServeStaticModule在文件中的導入數組中註冊 。app.module.ts

...
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

@Module({
  ...
  ServeStaticModule.forRoot({
    rootPath: join(__dirname, '..', 'files')
  }),],
  ...


在上面的代碼片段中,您已經指定了文件所在的位置並且可以從中提供服務。

測試 API

現在打開 Postman 並通過向端點發送 POST 請求來測試應用程序,並將localhost:4000/images請求正文中的有效負載作為表單數據傳遞。

我們的檔案

如果您現在查看文件文件夾,您應該會看到已上傳的文件。隨意繼續:測試並嘗試其他路線。

結論

通過本教程,您學習瞭如何使用 NestJS 和 MySQL 處理文件上傳。您已經學習瞭如何使用 TypeORM 連接到 MySQL 數據庫,並且您還創建了一個實體並將圖像上傳到 Nestjs 應用程序。

鏈接:https ://arctype.com/blog/nestjs-mysql-tutorial-fileuploads/

#nestjs #node #mysql #typeorm #database 

如何使用 NestJS 和 MySQL 處理文件上傳
Hans  Marvin

Hans Marvin

1659504720

How to Handle File Uploads with NestJS and MySQL

Many developers despise dealing with file uploads. This can be attributed to a lack of knowledge about the best approach to take or difficulties determining how to configure their Nest.js application to handle file uploads. Many people may want to save their files directly to a MySQL database, or save image names and have the image saved on disk storage: it all depends on their preferences and the goals they want to achieve. This tutorial will teach you how to build a file uploading functionality using Nestjs and MySQL.

In this blog, we will teach you how to build a file uploading functionality using NestJS and MySQL.

See more at: https://arctype.com/blog/nestjs-mysql-tutorial-fileuploads/

#nestjs #node  #mysql #typeorm #database 

How to Handle File Uploads with NestJS and MySQL
Thierry  Perret

Thierry Perret

1659497335

Comment Gérer Les Téléchargements De Fichiers Avec NestJS Et MySQL

Dans ce blog, nous allons vous apprendre à créer une fonctionnalité de téléchargement de fichiers à l'aide de NestJS et MySQL.

Introduction

De nombreux développeurs méprisent la gestion des téléchargements de fichiers. Cela peut être attribué à un manque de connaissances sur la meilleure approche à adopter ou à des difficultés à déterminer comment configurer leur application Nest.js pour gérer les téléchargements de fichiers. De nombreuses personnes peuvent souhaiter enregistrer leurs fichiers directement dans une base de données MySQL, ou enregistrer des noms d'image et enregistrer l'image sur un stockage sur disque : tout dépend de leurs préférences et des objectifs qu'ils souhaitent atteindre. Ce didacticiel vous apprendra à créer une fonctionnalité de téléchargement de fichiers à l'aide de Nestjs et MySQL.

Conditions préalables

Avant de commencer à suivre ce didacticiel, assurez-vous que votre système répond aux exigences suivantes :

  • Votre système exécute Node.js avec la version 14 ou ultérieure.
  • Votre système a une base de données MySQL installée.
  • Vous avez installé Postman .

Configurer NestJS

Une fois les exigences mentionnées ci-dessus remplies, procédez à l'installation de la CLI Nestjs et créez un nouveau projet en exécutant les commandes suivantes :

$ npm i -g @nestjs/cli
$ nest new file-upload

Ces commandes installeront la CLI Nestjs et créeront un nouveau projet Nestjs avec la structure de dossiers ci-dessous.

📦file-upload
┣ 📂src
┃ ┣ 📜app.controller.spec.ts
┃ ┣ 📜app.controller.ts
┃ ┣ 📜app.module.ts
┃ ┣ 📜app.service.ts
┃ ┣ 📜image.entity.ts
┃ ┗ 📜main.ts
┣ 📂test
┃ ┣ 📜app.e2e-spec.ts
┃ ┗ 📜jest-e2e.json
┣ 📜.eslintrc.js
┣ 📜.gitignore
┣ 📜.prettierrc
┣ 📜README.md
┣ 📜nest-cli.json
┣ 📜package-lock.json
┣ 📜package.json
┣ 📜tsconfig.build.json
┗ 📜tsconfig.json

Une fois le projet Nestjs créé, passez à l'étape suivante : installez les dépendances requises pour votre application en exécutant la commande suivante :

npm install --save @nestjs/typeorm typeorm mysql2

Dans la commande ci-dessus, vous avez installé les modules TypeORM et mysql2 : ils vont vous permettre de connecter votre application à une base de données MySQL et d'y effectuer des opérations.

Configurer la base de données MySQL

Une fois les dépendances ci-dessus installées, procédez à la configuration et à la connexion à votre base de données MySQL. Pour commencer, ajoutez le code dans le app.module.tsfichier avec l'extrait de code ci-dessous.

...
import { TypeOrmModule } from '@nestjs/typeorm';
import { Image } from './image.entity';

@Module({
  imports: [TypeOrmModule.forRoot({
    type: 'mysql',
    host: 'localhost',
    port: 3306,
    username: 'root',
    password: '1234',
    database: 'blog',
    entities: [Image],
    synchronize: true,
  }),
  TypeOrmModule.forFeature([Image])
  ],
  ...
})
...

Dans l'extrait de code ci-dessus, nous avons importé TypeOrmModuledu module typeorm que nous avons installé précédemment. Nous avons utilisé la forRootméthode pour connecter l'application à une base de données MySQL et transmettre les informations d'identification de la base de données. Une autre chose à souligner ici est que entitiesles propriétés, qui nous ont permis de spécifier les entités dans notre module et qui nous donneront accès à l' Imageentité que vous allez créer prochainement : nous avons également la synchronizepropriété définie sur truepour migrer automatiquement la base de données.

Créer une entité image

Ensuite, créons l'entité Image que nous avons mentionnée précédemment. Pour commencer, créez un fichier image.entity.ts dans le répertoire src et ajoutez l'extrait de code ci-dessous.

import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';

@Entity()
export class Image {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @CreateDateColumn()
    dateCreated: Date;

    @UpdateDateColumn()
    dateUpdated: Date;
}

Dans l'extrait de code ci-dessus, nous avons importé les décorateurs dont nous avons besoin pour créer une entité. En utilisant ces décorateurs, nous avons défini les propriétés de l'entité. Nous avons le idchamp pour générer des identifiants aléatoires pour chaque enregistrement dans la base de données à l'aide du @PrimaryGeneratedColumn()décorateur, le namechamp pour stocker les noms des images qui seront téléchargées à l'aide du @Columndécorateur, les champs dateCreated et dateUpdate pour enregistrer la date à laquelle un enregistrement a été créé et mis à jour en utilisant @CreateDateColumn()et @UpdateDateColumn().

Création du service de téléchargement

Une fois l'entité Image créée, créons un service pour effectuer les opérations CRUD afin de gérer les téléchargements de fichiers. Dans le app.service.tsfichier, ajoutez l'extrait de code ci-dessous.

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Image } from './image.entity';

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Image)
    private readonly imageRepository: Repository<Image>,
  ) {}

  async getImages(): Promise<Image[]> {
    return this.imageRepository.find();
  }

  async createImage(image: Image): Promise<Image> {
    return this.imageRepository.save(image);
  }

  async getImage(id: number): Promise<Image> {
    return this.imageRepository.findOneBy({ id });
  }

  async deleteImage(id: number): Promise<void> {
    await this.imageRepository.delete(id);
  }
}

Dans l'extrait de code ci-dessus, nous avons importé le injectRepositorydécorateur à injecter imageRepositorydans AppServiceet Repositoryqui vous fournit les méthodes nécessaires pour effectuer certaines opérations sur votre base de données. Donc, pour le createImageservice d'image, nous enregistrons le nom de l'image qui a été téléchargée et qui sera transmise au contrôleur.

Création du contrôleur de téléchargement

Créons maintenant les contrôleurs pour utiliser les services. Dans le app.controller.tsfichier et ajoutez l'extrait de code ci-dessous.

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Image } from './image.entity';

@Injectable()
export class AppService {
  constructor(
    @InjectRepository(Image)
    private readonly imageRepository: Repository<Image>,
  ) {}

  async getImages(): Promise<Image[]> {
    return this.imageRepository.find();
  }

  async createImage(image: Image): Promise<Image> {
    return this.imageRepository.save(image);
  }

  async getImage(id: number): Promise<Image> {
    return this.imageRepository.findOneBy({ id });
  }

  async deleteImage(id: number): Promise<void> {
    await this.imageRepository.delete(id);
  }
}

Dans l'extrait de code ci-dessus, nous avons importé quelques décorateurs comme FileInterceptor, UploadedFileet UseInterceptors. L' FileInterceptor()intercepteur du gestionnaire de route extrait le fichier de la requête à l'aide du @UploadedFile()décorateur. Le FileInterceptor()décorateur est exporté depuis le @nestjs/platform-expresspackage. Le @UploadedFile()décorateur est exporté depuis @nestjs/common. Le FileInterceptor()décorateur prend deux arguments, fieldNamequi est la chaîne qui fournit le nom du champ du formulaire HTML qui contient un fichier, et optionsqui est un objet facultatif de type MulterOptions. C'est le même objet utilisé par le constructeur multer.

En ce qui concerne la createImagefonction, nous avons utilisé les décorateurs susmentionnés pour gérer le téléchargement du fichier en FileInterceptor()passant le nom du champ pour l'image et nous avons modifié la FileInterceptor()fonction pour télécharger l'image sur le disque en spécifiant la storagepropriété à l'aide de la diskStoragefonction disponible dans multer. Ensuite, nous avons spécifié l'emplacement des images et généré des noms aléatoires pour les images. De plus, nous avons ajouté une filterpropriété pour restreindre le téléchargement de certains formats d'image. Maintenant, nous obtenons le fichier extrait à l'aide du @UploadedFile()décorateur et obtenons le nom et l'enregistrons dans la base de données. De cette façon, nous pouvons utiliser le nom de chaque image pour obtenir l'image de l'emplacement de stockage.

Pour que le code ci-dessus fonctionne, vous devez installer multer en exécutant la commande ci-dessous dans votre terminal :

npm i -D @types/multer


Ensuite, vous devez enregistrer le module multer dans le tableau des importations dans le app.module.tsfichier :

...
import { MulterModule } from '@nestjs/platform-express';


@Module({
  ...
  MulterModule.register({
    dest: './files',
  }),],
  ...

La configuration ci-dessus indique à multer de gérer le téléchargement du fichier et l'emplacement vers lequel télécharger le fichier. Enfin, nous devons créer un filesdossier dans le srcrépertoire pour stocker les fichiers.

Servir des fichiers

Pour réellement servir les images téléchargées sur votre application à l'utilisateur, vous devez installer le serve-staticmodule en exécutant la commande ci-dessous.

npm install --save @nestjs/serve-static

Ensuite, enregistrez le ServeStaticModuledans le tableau des importations dans le app.module.tsfichier avec l'extrait de code ci-dessous.

...
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';

@Module({
  ...
  ServeStaticModule.forRoot({
    rootPath: join(__dirname, '..', 'files')
  }),],
  ...


Dans l'extrait de code ci-dessus, vous avez spécifié l'emplacement où se trouvent les fichiers et à partir duquel ils peuvent être servis.

Tester l'API

Ouvrez maintenant Postman et testez l'application en envoyant une requête POST au point de terminaison localhost:4000/imageset transmettez la charge utile dans le corps de la requête en tant que données de formulaire.

Notre dossier

Si vous regardez maintenant le dossier des fichiers, vous devriez voir le fichier que vous avez téléchargé. N'hésitez pas à aller de l'avant : testez et jouez également avec d'autres itinéraires.

Conclusion

Grâce à ce didacticiel, vous avez appris à gérer le téléchargement de fichiers avec NestJS et MySQL. Vous avez appris à vous connecter à une base de données MySQL à l'aide de TypeORM et vous avez également créé une entité et téléchargé des images dans l'application Nestjs.

Lien : https://arctype.com/blog/nestjs-mysql-tutorial-fileuploads/

#nestjs #node #mysql #typeorm #database 

Comment Gérer Les Téléchargements De Fichiers Avec NestJS Et MySQL
许 志强

许 志强

1658635500

如何将 Redis 缓存添加到 NestJS 应用程序

性能,性能,性能!这就是缓存的全部意义所在。

缓存特别有助于加快应用程序的性能,从而显着提高其效率。

本文将介绍如何使用 Redis 向 NestJS 应用程序添加缓存功能。我们将讨论什么是缓存,关于 Redis,并回顾实现过程。

所以喝杯咖啡(或者这些天你们都喝的任何东西)。这将是一个有趣的!

什么是缓存?

在计算中,缓存是重复数据的频繁查询的临时存储。数据保存在易于访问的位置以减少延迟。

让我做一个类比来帮助更好地解释这个概念……

假设你确实得到了那杯咖啡!想象一下,每次你喝一点,你都必须回到你的咖啡机旁。你把杯子装满,喝一口,然后把它放在那里,回到你的工作站,继续阅读这篇文章。

因为你必须不断地来回使用你的咖啡机和杯子,所以你需要几个小时才能喝完咖啡(还有这篇文章)。这就是在没有缓存的情况下发生的情况。

让我们想象一个不同的场景。假设当您前往咖啡机喝第一口咖啡时,您不是喝了一口然后回到工作区,而是装满杯子,然后拿着它回到工作站。

当您继续阅读本文时,您的办公桌上总是有咖啡。您可以快速喝一口(降低延迟),这样您就可以专注于这篇文章并更快地完成它。这就是实现缓存时发生的情况

如果我们把这个类比到现实世界,咖啡机就是网络服务器,而咖啡本身就是经常被查询的数据。

什么是 Redis?

根据Redis 官方网站,“Redis 是一个开源的内存数据结构存储,用作数据库、缓存、消息代理和流引擎。”

需要注意的是,Redis 并不单独处理缓存。它提供数据结构,如散列、集合、字符串、列表、位图和排序集合以及范围查询、流、HyperLogLogs 和地理空间索引。

在 NestJS 应用中实现 Redis 缓存

先决条件

要继续阅读本文,您需要以下内容:

  • 安装在您的计算机上的 Node.js
  • JavaScript 和 Node.js 的基础知识
  • NestJS 命令行界面 (CLI) 安装在您的计算机上
  • 基本了解 Nest 的工作原理

如果您没有安装 NestJS,这将帮助您快速上手

在您的机器上安装 NestJS CLI 之后,让我们继续为我们的应用程序设置 Redis 缓存。

为我们的 NestJS 应用设置 Redis 缓存

首先,让我们创建一个新项目。我们会调用它redis-setup。安装 NestJS 后打开终端并运行以下代码行:

nest new redis-setup

之后,我们要选择我们喜欢的包管理器。

包管理器截图

就我而言,我选择了,npm但请选择适合您的!之后,安装将继续。

安装完成后,我们将看到类似于以下屏幕截图的内容。我们必须cd通过运行进入我们的应用程序cd redis-setup

cd 进入 Redis 设置截图

进入项目目录后,我们将code在终端中运行。这将自动在 VS Code 中打开项目,前提是它已安装。

VS 代码

下面是我们的redis-setup项目的样子。

Redis 设置项目截图

在我们继续我们的设置之前,我们需要在我们的应用程序中安装四个主要的包。

安装包

我们需要安装的第一个包是node-cache-manager. Node 缓存模块管理器允许在缓存、分层缓存和一致的接口中轻松包装函数。npm install cache-manager通过在终端中运行来安装它。

接下来,我们需要@types/cache-manager安装node-cache-manager. npm i @types/cache-manager通过在终端中运行来安装它。

第三,我们将安装cache-manager-redis-store. 这个包提供了一个非常简单的包装器,用于将配置传递给node_redis包。npm install cache-manager-redis-store --save通过在终端中运行来安装它

最后,我们需要安装@types/cache-manager-redis-store. 这是cache-manager-redis-store包的 TypeScript 实现。npm i --save-dev @types/cache-manager-redis-store通过在终端中运行来安装它。

安装完成后,我们可以继续redis-cache为我们的应用程序进行配置。

配置redis-cache

配置的第一步redis-cache是导入CacheModule并调用它的方法register()。此方法将采用我们的 Redis 配置。

//import CacheModule from @nestjs/common'

import { Module, CacheModule } from '@nestjs/common';

在我们的register()中,它接受一个对象,我们将创建一个名为store并分配redisStore给它的属性。将redisStore代表cache-manager-redis-store我们安装的库。

//import CacheModule from '@neskjs/common/cache';
import { Module, CacheModule } from '@nestjs/common';

//import redisStore from 'cache-manager-redis-store';
import * as redisStore from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [CacheModule.register({ store: redisStore })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

register()接下来,我们将在方法对象中设置另一个属性。我们将添加另一个名为的属性host并将其值设置为 default localhost。我们将 设置port为 的默认值6379

//import CacheModule from '@neskjs/common/cache';
import { Module, CacheModule } from '@nestjs/common';

//import redisStore from 'cache-manager-redis-store';
import * as redisStore from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [CacheModule.register({ 
    store: redisStore, 
    host: 'localhost', //default host
    port: 6379 //default port
  })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

通过以上,我们在 Redis 和我们的 NestJS 应用程序之间建立了一个简单的基本配置!

第二步是将功能注入我们的控制器。这样我们的控制器就可以与 Redis 存储进行通信。我们需要注入CacheManager.

在我们的项目目录中,转到app.controller.ts. 在此文件中,我们将导入GetInjectCACHE_MANAGERfrom @nestjs/common

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import { Controller, Get, Inject, CACHE_MODULE } from '@nestjs/common';

之后,我们将传入Inject令牌CACHE_MANAGER。接下来,我们将从中导入Cache并将cache-manager其传递给我们的cacheManager.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import { Controller, Get, Inject, CACHE_MANAGER } from '@nestjs/common';
//import the cache manager
import Cache from 'cache-manager';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache{}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

注意Cache该类是从cache-manager库中导入的,而CACHE_MANAGER令牌是从@nestjs/common.

CACHE_MANAGER注入redis-cache-store, 同时Cache提供默认的通信方法,Cache也适用于任何其他商店。

下面我们来了解一下Redis store的getset方法。

getset方法

Cache实例具有get我们从cache-manager包中获得的方法。此方法使我们能够从缓存中获取项目。null如果缓存为空,则返回。

let val = await this.cacheManager.get('key');

我们使用get将项目添加到缓存的方法。默认缓存时间为 5 秒,但我们可以手动将生存时间 (TTL) 设置为我们需要的任何时间。这将取决于应用程序的规格。

await this.cacheManager.set('key', 'value', {ttl: 2000});

在我们的get方法中,我们将传递用于检查 Redis 存储的 URL。

@Get('get-number-cache')

接下来,在我们的 中app.controller.ts,我们将创建一个获取数字的方法。我们将使用字符串检查我们的号码是否在 Redis 存储中可用number

const val = await this.cacheManager.get('number')
    if(val) {
      return { 
        data: val,
        FromRedis: 'this is loaded from redis cache'
      }
    }

如果是这种情况,我们会将数据返回到我们的端点。但是,如果数据不存在于 中redis-store,我们使用键存储它number并将 TTL 设置为任何所需的值。在我们的例子中,我们将使用1000.

最后,我们将从我们的虚拟数据库中返回存储的数据randomNumDbs。在这种情况下,我们随机生成数字。我们可以使用字符串,但在现实世界的生产应用程序中,我们将从数据库中为每个第一个请求获取数据。

if(!val){
      await this.cacheManager.set('number', this.randomNumDbs , { ttl: 1000 })
      return {
        data: this.randomNumDbs,
        FromRandomNumDbs: 'this is loaded from randomNumDbs'
    }

下面是完整的代码:

@Controller()
export class AppController {
  //This would be our dummy database since we won't be connecting to a database in the article
  randomNumDbs = Math.floor(Math.random() * 10)
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

  @Get('get-number-cache')
  async getNumber(): Promise<any> {
    const val = await this.cacheManager.get('number')
    if(val) {
      return { 
        data: val,
        FromRedis: 'this is loaded from redis cache'
      }
    }

    if(!val){
      await this.cacheManager.set('number', this.randomNumDbs , { ttl: 1000 })
      return {
        data: this.randomNumDbs,
        FromRandomNumDbs: 'this is loaded from randomNumDbs'
    }
  }
}

现在是时候运行我们的应用程序并测试我们迄今为止所做的工作了。要在终端中执行此操作,请在浏览器中运行npm start并访问 URL http://localhost:3000/get-number-cache

在我们第一次加载时,我们的请求将从我们的虚拟随机数数据库中获取。

随机数数据库请求

第二个请求(和其他请求)将从 Redis 存储加载,直到缓存数据过期。

加载的 Redis 缓存

Redis 缓存还有另外两种方法:delreset.

delreset方法

如果它还不是不言自明的,该del方法可以帮助我们从缓存中删除一个项目。

await this.cacheManager.del('number');

reset另一方面,该方法清除整个 Redis 存储缓存

await this.cacheManager.reset();

使用拦截器设置自动缓存

自动缓存Get使用CacheInterceptor.

在我们的app.module.ts文件中,我们将导入CacheInterceptor. TTL使用该属性为我们的自动缓存全局配置过期时间。要启用CacheInterceptor,我们需要将它导入到数组providers中。

//import CacheModule from '@neskjs/common/cache';
import { Module, CacheModule, CacheInterceptor } from '@nestjs/common';

//import redisStore from 'cache-manager-redis-store';
import * as redisStore from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { APP_INTERCEPTOR } from '@nestjs/core';

@Module({
  imports: [CacheModule.register({ 
    store: redisStore, 
    host: 'localhost', //default host
    port: 6379, //default port
    ttl: 2000, //ttl
  })],
  controllers: [AppController],
  providers: [
    {
      provide:APP_INTERCEPTOR,
      useClass: CacheInterceptor
    },
    AppService],
})
export class AppModule {}

接下来,在 中,我们从中app.controller.ts导入UseInterceptor和。CacheInterceptor@nestjs/common

import { Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor } from '@nestjs/common';

我们UseInterceptors直接使用我们下面的装饰器@controller()并传递CacheInterceptor给它。这将为Get控制器内的所有端点启用自动缓存。

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import {Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor} from '@nestjs/common';
//import the cache manager
import {Cache} from 'cache-manager';
import { AppService } from './app.service';
//import Profile.ts
import {User} from './shared/model/User';

@UseInterceptors(CacheInterceptor)
@Controller()
export class AppController {
  fakeModel:User = {
    id: 1,
    name: 'John Doe',
    email: 'okee@gmail.com',
    phone: '123456789',
    address: '123 Main St',
    createdAt: new Date(),
  }

  @Get('auto-caching')
  getAutoCaching() {
    return this.fakeModel;
  }
}

对于自动缓存,keyroute值。这是将存储在我们的缓存中的内容,如下面的屏幕截图所示。

关键路线价值

我们可以通过输入keys *命令在 CLI 中确认这一点。

在我们想要存储特定路由的数据的情况下,我们不会使用全局定义的timeand key。我们可以自定义我们的方法以有不同的时间。

app.controller.ts中,我们使用了一个名为@CacheTTL(). 对于唯一键,我们使用另一个装饰器@CacheKey(),从@nestjs/common.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import {Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor, CacheKey, CacheTTL} from '@nestjs/common';

指定将数据保存到 Redis 存储中的字符串和控制器的私有时间。

@Get('auto-caching')
  @CacheKey('auto-caching-fake-model')
  @CacheTTL(10)
  getAutoCaching() {
    return this.fakeModel;
  }

文件自动缓存代码的完整代码app.controller.ts如下。

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import {Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor, CacheKey, CacheTTL} from '@nestjs/common';
//import the cache manager
import {Cache} from 'cache-manager';
import { AppService } from './app.service';
//import Profile.ts
import {User} from './shared/model/User';

@UseInterceptors(CacheInterceptor)
@Controller()
export class AppController {
  fakeModel:User = {
    id: 1,
    name: 'John Doeeee',
    email: 'okee@gmail.com',
    phone: '123456789',
    address: '123 Main St',
    createdAt: new Date(),
  }

  @Get('auto-caching')
  @CacheKey('auto-caching-fake-model')
  @CacheTTL(10)
  getAutoCaching() {
    return this.fakeModel;
  }
}

结论

而已!在本文中,我们介绍了如何将 Redis 缓存添加到 NestJS 应用程序。

Redis 可实现更低的应用程序延迟和非常高的数据访问。这使软件工程师能够构建高性能、可靠的解决方案。

在我看来,Redis 的优点大于缺点(如果有的话)。我希望我已经分享了一些关于 NestJS 和 Redis 存储如何工作的深入信息!

如果你喜欢这篇文章,请在评论区发表评论!谢谢你陪我到最后。再见!!!

来源:https ://blog.logrocket.com/add-redis-cache-nestjs-app/

 #nestjs #redis 

如何将 Redis 缓存添加到 NestJS 应用程序

Como Adicionar O Cache Redis A Um Aplicativo NestJS

Desempenho, desempenho, desempenho! Esse é o ponto de cache.

O cache especificamente ajuda a acelerar o desempenho de um aplicativo, melhorando significativamente sua eficiência.

Este artigo analisará como adicionar a funcionalidade de armazenamento em cache a um aplicativo NestJS com Redis. Falaremos sobre o que é cache, sobre o Redis e falaremos sobre o processo de implementação.

Então pegue uma xícara de café (ou seja lá o que você bebe hoje em dia). Essa vai ser interessante!

O que é cache?

Na computação, um cache é um armazenamento temporário e consultado com frequência de dados duplicados. Os dados são mantidos em um local de fácil acesso para reduzir a latência.

Deixe-me fazer uma analogia para ajudar a explicar melhor esse conceito…

Digamos que você tenha tomado aquela xícara de café depois de tudo! Imagine que cada vez que você bebe um pouco, você tem que voltar para sua máquina de café. Você enche seu copo, toma um gole e o deixa lá para voltar para sua estação de trabalho e continuar lendo este artigo.

Como você tem que ficar indo e voltando para sua máquina de café e xícara, leva várias horas para terminar seu café (e este artigo). Isso é o que acontece sem cache.

Vamos imaginar um cenário diferente. Digamos que quando você se dirige à sua máquina de café para o primeiro gole de café, em vez de tomar um gole e voltar para o seu espaço de trabalho, você enche a xícara e volta para a estação de trabalho com ela na mão.

Ao continuar lendo este artigo, você sempre toma seu café em sua mesa. Você pode tomar um gole rapidamente (latência mais baixa) para se concentrar neste artigo e terminá-lo muito mais rápido. Isto é o que acontece quando o cache é implementado .

Se quisermos trazer essa analogia para o mundo real, a máquina de café é o servidor web e o próprio café são os dados frequentemente consultados.

O que é Redis?

De acordo com o site oficial do Redis , “o Redis é um armazenamento de estrutura de dados na memória de código aberto usado como banco de dados, cache, agente de mensagens e mecanismo de streaming”.

É importante observar que o Redis não lida com o cache sozinho . Ele fornece estruturas de dados como hashes, conjuntos, strings, listas, bitmaps e conjuntos classificados com consultas de intervalo, fluxos, HyperLogLogs e índices geoespaciais.

Implementando o cache Redis em um aplicativo NestJS

Pré-requisitos

Para acompanhar este artigo, você precisará do seguinte:

  • Node.js instalado em seu computador
  • Conhecimento básico de JavaScript e Node.js
  • NestJS Command Line Interface (CLI) instalada em seu computador
  • Compreensão básica de como o Nest funciona

Se você não tiver o NestJS instalado, isso o ajudará a se atualizar .

Depois de instalar o NestJS CLI em sua máquina, vamos em frente e configurar o cache Redis para nosso aplicativo.

Configurando o cache Redis para nosso aplicativo NestJS

Primeiro, vamos criar um novo projeto. Nós vamos chamá-lo redis-setup. Abra o terminal após instalar o NestJS e execute a linha de código abaixo:

nest new redis-setup

Depois disso, queremos selecionar nosso gerenciador de pacotes preferido.

Captura de tela do gerenciador de pacotes

No meu caso, eu escolhi npm, mas por favor, escolha o que funciona para você! Depois disso, a instalação continuará.

Quando a instalação estiver concluída, veremos algo semelhante à captura de tela abaixo. Temos que cdentrar em nosso aplicativo executando cd redis-setup.

Captura de tela de configuração de CD no Redis

Uma vez dentro do diretório do projeto, executaremos codeno terminal. Isso abrirá automaticamente o projeto no VS Code, desde que esteja instalado.

Código VS

Abaixo está como é o nosso redis-setupprojeto.

Captura de tela do projeto de configuração do Redis

Antes de continuarmos nossa configuração, existem quatro pacotes principais que precisamos instalar em nosso aplicativo.

Instalando pacotes

O primeiro pacote que precisamos instalar é o node-cache-manager. O gerenciador de módulo de cache Node permite o agrupamento fácil de funções em cache, caches em camadas e uma interface consistente. Instale isso executando npm install cache-managerno terminal.

Em seguida, precisamos instalar @types/cache-managero , a implementação do TypeScript do node-cache-manager. Instale isso executando npm i @types/cache-managerno terminal.

Terceiro, instalaremos o cache-manager-redis-store. Este pacote fornece um wrapper muito fácil para passar a configuração para o node_redispacote. Instale isso executando npm install cache-manager-redis-store --saveno terminal

Por fim, precisamos instalar o @types/cache-manager-redis-store. Esta é a implementação TypeScript do cache-manager-redis-storepacote. Instale isso executando npm i --save-dev @types/cache-manager-redis-storeno terminal.

Depois que terminarmos a instalação, podemos prosseguir com a configuração redis-cachedo nosso aplicativo.

Configurandoredis-cache

O primeiro passo para configurar redis-cacheé importar CacheModulee chamar seu método register(). Esse método usará nossas configurações do Redis.

//import CacheModule from @nestjs/common'

import { Module, CacheModule } from '@nestjs/common';

No nosso register(), que recebe um objeto, vamos criar uma propriedade chamada storee atribuir redisStorea ela. O redisStorerepresentará a cache-manager-redis-storebiblioteca que instalamos.

//import CacheModule from '@neskjs/common/cache';
import { Module, CacheModule } from '@nestjs/common';

//import redisStore from 'cache-manager-redis-store';
import * as redisStore from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [CacheModule.register({ store: redisStore })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Em seguida, vamos configurar outra propriedade no register()objeto do método. Adicionaremos outra propriedade chamada hoste definiremos seu valor para o padrão localhost. Vamos definir o portvalor padrão de 6379.

//import CacheModule from '@neskjs/common/cache';
import { Module, CacheModule } from '@nestjs/common';

//import redisStore from 'cache-manager-redis-store';
import * as redisStore from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [CacheModule.register({ 
    store: redisStore, 
    host: 'localhost', //default host
    port: 6379 //default port
  })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Com o acima, configuramos uma configuração simples e básica entre o Redis e nosso aplicativo NestJS!

O segundo passo é injetar a funcionalidade em nosso controller. Isso é para que nossos controladores possam se comunicar com a loja Redis. Precisamos injetar CacheManager.

Em nosso diretório de projetos, vá para app.controller.ts. Neste arquivo, importaremos Get, Injecte CACHE_MANAGERde @nestjs/common.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import { Controller, Get, Inject, CACHE_MODULE } from '@nestjs/common';

Depois disso, passaremos Injecte o CACHE_MANAGERtoken. Em seguida, vamos importá Cache- cache-managerlo e passá-lo para o nosso arquivo cacheManager.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import { Controller, Get, Inject, CACHE_MANAGER } from '@nestjs/common';
//import the cache manager
import Cache from 'cache-manager';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache{}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

NB , A Cacheclasse é importada da cache-managerbiblioteca, enquanto o CACHE_MANAGERtoken é importado do @nestjs/common.

O CACHE_MANAGERinjeta o redis-cache-store, while Cachefornece o método padrão para Cachecomunicação e também funciona com qualquer outra loja.

Vamos entender os métodos gete setda loja Redis.

gete setmétodos

A Cacheinstância tem o getmétodo, que temos do cache-managerpacote. Este método nos permite obter itens do cache. nullé retornado se o cache estiver vazio.

let val = await this.cacheManager.get('key');

Usamos o getmétodo para adicionar um item ao cache. O tempo de cache padrão é de cinco segundos, mas podemos definir manualmente o tempo de vida (TTL) para qualquer momento que precisarmos. Vai depender das especificações do aplicativo.

await this.cacheManager.set('key', 'value', {ttl: 2000});

Em nosso getmétodo, passaremos a URL para verificar nossa loja Redis.

@Get('get-number-cache')

Em seguida, em nosso app.controller.ts, criaremos um método que obtém um número. Verificaremos se nosso número está disponível na loja Redis usando a string number.

const val = await this.cacheManager.get('number')
    if(val) {
      return { 
        data: val,
        FromRedis: 'this is loaded from redis cache'
      }
    }

Se for esse o caso, retornaremos os dados ao nosso endpoint. Mas, se os dados não existirem em redis-store, nós os armazenamos usando a chave numbere definimos o TTL para qualquer valor desejado. No nosso caso, usaremos 1000.

Por fim, retornaremos os dados armazenados de nosso banco de dados fictício randomNumDbs. Nesse caso, estamos gerando o número aleatoriamente. Poderíamos usar uma string, mas em um aplicativo de produção do mundo real, é aqui que obteríamos os dados do banco de dados para cada primeira solicitação.

if(!val){
      await this.cacheManager.set('number', this.randomNumDbs , { ttl: 1000 })
      return {
        data: this.randomNumDbs,
        FromRandomNumDbs: 'this is loaded from randomNumDbs'
    }

Abaixo segue o código completo:

@Controller()
export class AppController {
  //This would be our dummy database since we won't be connecting to a database in the article
  randomNumDbs = Math.floor(Math.random() * 10)
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

  @Get('get-number-cache')
  async getNumber(): Promise<any> {
    const val = await this.cacheManager.get('number')
    if(val) {
      return { 
        data: val,
        FromRedis: 'this is loaded from redis cache'
      }
    }

    if(!val){
      await this.cacheManager.set('number', this.randomNumDbs , { ttl: 1000 })
      return {
        data: this.randomNumDbs,
        FromRandomNumDbs: 'this is loaded from randomNumDbs'
    }
  }
}

Agora é hora de executar nosso aplicativo e testar o que fizemos até agora. Para fazer isso no terminal, execute npm starte visite a URL http://localhost:3000/get-number-cache no navegador.

Em nosso primeiro carregamento, nossa solicitação será retirada de nosso banco de dados fictício de números aleatórios.

Solicitação de banco de dados de números aleatórios

A segunda solicitação (e outras) será carregada do armazenamento Redis até que os dados armazenados em cache expirem.

Cache Redis carregado

O cache Redis também tem dois outros métodos: dele reset.

dele resetmétodos

Se ainda não for autoexplicativo, o delmétodo nos ajuda a remover um item do cache.

await this.cacheManager.del('number');

O resetmétodo, por outro lado, limpa todo o cache da loja Redis

await this.cacheManager.reset();

Configurando o cache automático usando o Interceptor

O cache automático habilita o cache para cada Getmétodo de ação dentro do controlador usando o CacheInterceptor.

Em nosso app.module.tsarquivo, vamos importar CacheInterceptor. Configure a expiração globalmente para nosso cache automático, usando a TTLpropriedade. Para habilitar CacheInterceptor, precisamos importá-lo para o array providers.

//import CacheModule from '@neskjs/common/cache';
import { Module, CacheModule, CacheInterceptor } from '@nestjs/common';

//import redisStore from 'cache-manager-redis-store';
import * as redisStore from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { APP_INTERCEPTOR } from '@nestjs/core';

@Module({
  imports: [CacheModule.register({ 
    store: redisStore, 
    host: 'localhost', //default host
    port: 6379, //default port
    ttl: 2000, //ttl
  })],
  controllers: [AppController],
  providers: [
    {
      provide:APP_INTERCEPTOR,
      useClass: CacheInterceptor
    },
    AppService],
})
export class AppModule {}

Em seguida, em app.controller.ts, importamos o UseInterceptore CacheInterceptorde @nestjs/common.

import { Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor } from '@nestjs/common';

Usamos o UseInterceptorsdecorador diretamente sob o nosso @controller()e passamos CacheInterceptorpara ele. Isso habilitará o cache automático para todos os nossos Getendpoints dentro do controlador.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import {Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor} from '@nestjs/common';
//import the cache manager
import {Cache} from 'cache-manager';
import { AppService } from './app.service';
//import Profile.ts
import {User} from './shared/model/User';

@UseInterceptors(CacheInterceptor)
@Controller()
export class AppController {
  fakeModel:User = {
    id: 1,
    name: 'John Doe',
    email: 'okee@gmail.com',
    phone: '123456789',
    address: '123 Main St',
    createdAt: new Date(),
  }

  @Get('auto-caching')
  getAutoCaching() {
    return this.fakeModel;
  }
}

Para cache automático, keyé o routevalor. Isso é o que será armazenado em nosso cache, mostrado na captura de tela abaixo.

Valor da rota chave

Podemos confirmar isso em nossa CLI inserindo o keys *comando.

Nos casos em que queremos armazenar dados para uma rota específica, não usaremos o timee key. Podemos personalizar nosso método para ter um horário diferente.

Em app.controller.ts, usamos um decorador chamado @CacheTTL(). Para a chave exclusiva, usamos outro decorador @CacheKey(), importado de @nestjs/common.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import {Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor, CacheKey, CacheTTL} from '@nestjs/common';

Especifique uma string que salvará os dados no armazenamento Redis e um horário privado para nosso controlador.

@Get('auto-caching')
  @CacheKey('auto-caching-fake-model')
  @CacheTTL(10)
  getAutoCaching() {
    return this.fakeModel;
  }

O código completo para o app.controller.tscódigo de cache automático do arquivo está abaixo.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import {Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor, CacheKey, CacheTTL} from '@nestjs/common';
//import the cache manager
import {Cache} from 'cache-manager';
import { AppService } from './app.service';
//import Profile.ts
import {User} from './shared/model/User';

@UseInterceptors(CacheInterceptor)
@Controller()
export class AppController {
  fakeModel:User = {
    id: 1,
    name: 'John Doeeee',
    email: 'okee@gmail.com',
    phone: '123456789',
    address: '123 Main St',
    createdAt: new Date(),
  }

  @Get('auto-caching')
  @CacheKey('auto-caching-fake-model')
  @CacheTTL(10)
  getAutoCaching() {
    return this.fakeModel;
  }
}

Conclusão

É isso! Neste artigo, vimos como adicionar o cache Redis a um aplicativo NestJS.

O Redis permite menor latência de aplicativos e acesso a dados muito alto. Isso permitiu que os engenheiros de software construíssem soluções confiáveis ​​e de alto desempenho.

Na minha opinião, as vantagens do Redis superam as desvantagens (se houver). Espero ter compartilhado algumas informações detalhadas sobre como o NestJS e a loja Redis funcionam!

Se você gostou deste artigo, por favor, comente na seção de comentários! Obrigado por ficar comigo até o final desta. Tchau!!!

Fonte: https://blog.logrocket.com/add-redis-cache-nestjs-app/

  #nestjs #redis 

Como Adicionar O Cache Redis A Um Aplicativo NestJS

Cómo Agregar Caché Redis A Una Aplicación NestJS

¡Rendimiento, rendimiento, rendimiento! Ese es el objetivo del almacenamiento en caché.

El almacenamiento en caché ayuda específicamente a acelerar el rendimiento de una aplicación, lo que mejora significativamente su eficiencia.

Este artículo analizará cómo agregar la funcionalidad de almacenamiento en caché a una aplicación NestJS con Redis. Hablaremos sobre qué es el almacenamiento en caché, sobre Redis y repasaremos el proceso de implementación.

Así que tome una taza de café (o lo que sea que todos beben en estos días). ¡Esto va a ser interesante!

¿Qué es el almacenamiento en caché?

En informática, un caché es un almacén temporal de datos duplicados consultado con frecuencia. Los datos se guardan en una ubicación de fácil acceso para reducir la latencia.

Permítanme formar una analogía para ayudar a explicar mejor este concepto...

¡Digamos que sí consiguió esa taza de café después de todo! Imagina que cada vez que bebes un poco, tienes que volver a tu máquina de café. Llenas tu taza, tomas un sorbo y lo dejas allí para regresar a tu estación de trabajo y continuar leyendo este artículo.

Debido a que tienes que ir y venir de tu máquina de café a tu taza, te lleva varias horas terminar tu café (y este artículo). Esto es lo que sucede sin almacenamiento en caché.

Imaginemos un escenario diferente. Digamos que cuando se dirige a su máquina de café para su primer sorbo de café, en lugar de tomar un sorbo y regresar a su espacio de trabajo, llena su taza y regresa a su estación de trabajo con ella en la mano.

A medida que continúa leyendo este artículo, siempre tiene su café en su escritorio. Puede tomar un sorbo rápidamente (menor latencia) para que pueda concentrarse en este artículo y terminarlo mucho más rápido. Esto es lo que sucede cuando se implementa el almacenamiento en caché .

Si llevamos esta analogía al mundo real, la máquina de café es el servidor web y el café en sí mismo es la información que se consulta con frecuencia.

¿Qué es Redis?

Según el sitio web oficial de Redis , "Redis es un almacén de estructura de datos en memoria de código abierto que se utiliza como base de datos, caché, intermediario de mensajes y motor de transmisión".

Es importante tener en cuenta que Redis no maneja solo el almacenamiento en caché . Proporciona estructuras de datos como hashes, conjuntos, cadenas, listas, mapas de bits y conjuntos ordenados con consultas de rango, secuencias, HyperLogLogs e índices geoespaciales.

Implementación de caché de Redis en una aplicación NestJS

requisitos previos

Para seguir este artículo, necesitará lo siguiente:

  • Node.js instalado en su computadora
  • Conocimientos básicos de JavaScript y Node.js
  • Interfaz de línea de comandos (CLI) de NestJS instalada en su computadora
  • Comprensión básica de cómo funciona Nest

Si no tiene NestJS instalado, esto lo ayudará a ponerse al día .

Una vez que haya instalado la CLI de NestJS en su máquina, sigamos adelante y configuremos el caché de Redis para nuestra aplicación.

Configuración de caché de Redis para nuestra aplicación NestJS

Primero, vamos a crear un nuevo proyecto. Lo llamaremos redis-setup. Abra la terminal después de instalar NestJS y ejecute la siguiente línea de código:

nest new redis-setup

Después de eso, queremos seleccionar nuestro administrador de paquetes preferido.

Captura de pantalla del administrador de paquetes

En mi caso, elegí, ¡ npmpero elija lo que funcione para usted! Después de eso, la instalación continuará.

Una vez finalizada la instalación, veremos algo similar a la siguiente captura de pantalla. Tenemos que cdentrar en nuestra aplicación ejecutando cd redis-setup.

Captura de pantalla de configuración de Cd Into Redis

Una vez dentro del directorio del proyecto, ejecutaremos codeen la terminal. Esto abrirá automáticamente el proyecto en VS Code, siempre que esté instalado.

Código VS

A continuación se muestra cómo se ve nuestro redis-setupproyecto.

Captura de pantalla del proyecto de instalación de Redis

Antes de continuar con nuestra configuración, hay cuatro paquetes principales que debemos instalar en nuestra aplicación.

Instalando paquetes

El primer paquete que necesitamos instalar es node-cache-manager. El administrador de módulos de caché de Node permite envolver fácilmente funciones en caché, cachés en niveles y una interfaz consistente. Instale esto ejecutando npm install cache-manageren la terminal.

A continuación, necesitamos instalar @types/cache-manager, la implementación de TypeScript de node-cache-manager. Instale esto ejecutando npm i @types/cache-manageren la terminal.

En tercer lugar, instalaremos cache-manager-redis-store. Este paquete proporciona un contenedor muy sencillo para pasar la configuración al node_redispaquete. Instale esto ejecutando npm install cache-manager-redis-store --saveen la terminal

Finalmente, necesitamos instalar @types/cache-manager-redis-store. Esta es la implementación de TypeScript del cache-manager-redis-storepaquete. Instale esto ejecutando npm i --save-dev @types/cache-manager-redis-storeen la terminal.

Una vez que hayamos terminado con la instalación, podemos proceder a configurar redis-cachenuestra aplicación.

configurandoredis-cache

El primer paso para configurar redis-cachees importar CacheModuley llamar a su método register(). Este método tomará nuestras configuraciones de Redis.

//import CacheModule from @nestjs/common'

import { Module, CacheModule } from '@nestjs/common';

En nuestro register(), que toma un objeto, crearemos una propiedad llamada storey se la asignaremos redisStore. El redisStorerepresentará la cache-manager-redis-storebiblioteca que instalamos.

//import CacheModule from '@neskjs/common/cache';
import { Module, CacheModule } from '@nestjs/common';

//import redisStore from 'cache-manager-redis-store';
import * as redisStore from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [CacheModule.register({ store: redisStore })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

A continuación, configuraremos otra propiedad en el register()objeto de método. Agregaremos otra propiedad llamada hosty estableceremos su valor en el valor predeterminado localhost. Estableceremos el portvalor predeterminado de 6379.

//import CacheModule from '@neskjs/common/cache';
import { Module, CacheModule } from '@nestjs/common';

//import redisStore from 'cache-manager-redis-store';
import * as redisStore from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [CacheModule.register({ 
    store: redisStore, 
    host: 'localhost', //default host
    port: 6379 //default port
  })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

¡Con lo anterior, hemos establecido una configuración básica simple entre Redis y nuestra aplicación NestJS!

El segundo paso es inyectar la funcionalidad en nuestro controlador. Esto es para que nuestros controladores puedan comunicarse con la tienda Redis. Tenemos que inyectar CacheManager.

En nuestro directorio de proyectos, diríjase a app.controller.ts. En este archivo, importaremos Get, Injecty CACHE_MANAGERdesde @nestjs/common.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import { Controller, Get, Inject, CACHE_MODULE } from '@nestjs/common';

Después de eso, pasaremos Injecty el CACHE_MANAGERtoken. A continuación, importaremos Cachedesde cache-managery lo pasaremos a nuestro archivo cacheManager.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import { Controller, Get, Inject, CACHE_MANAGER } from '@nestjs/common';
//import the cache manager
import Cache from 'cache-manager';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache{}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

NB , la Cacheclase se importa de la cache-managerbiblioteca, mientras que el CACHE_MANAGERtoken se importa de @nestjs/common.

El CACHE_MANAGERinyecta el redis-cache-store, mientras Cacheproporciona el método predeterminado para la Cachecomunicación y también funciona con cualquier otra tienda.

Comprendamos los métodos gety de la tienda Redis.set

gety setmetodos

La Cacheinstancia tiene el getmétodo, que tenemos del cache-managerpaquete. Este método nos permite obtener elementos del caché. nullse devuelve si la memoria caché está vacía.

let val = await this.cacheManager.get('key');

Usamos el getmétodo para agregar un elemento al caché. El tiempo de almacenamiento en caché predeterminado es de cinco segundos, pero podemos configurar manualmente el tiempo de vida (TTL) en cualquier momento que necesitemos. Dependerá de las especificaciones de la aplicación.

await this.cacheManager.set('key', 'value', {ttl: 2000});

En nuestro getmétodo, pasaremos la URL para verificar nuestra tienda Redis.

@Get('get-number-cache')

A continuación, en nuestro app.controller.ts, crearemos un método que obtenga un número. Verificaremos si nuestro número está disponible en la tienda de Redis usando la cadena number.

const val = await this.cacheManager.get('number')
    if(val) {
      return { 
        data: val,
        FromRedis: 'this is loaded from redis cache'
      }
    }

Si este es el caso, devolveremos los datos a nuestro punto final. Pero, si los datos no existen en redis-store, los almacenamos usando la clave numbery establecemos el TTL en cualquier valor deseado. En nuestro caso, usaremos 1000.

Finalmente, devolveremos los datos almacenados de nuestra base de datos ficticia randomNumDbs. En este caso, estamos generando el número aleatoriamente. Podríamos usar una cadena, pero en una aplicación de producción del mundo real, aquí es donde obtendríamos los datos de la base de datos para cada primera solicitud.

if(!val){
      await this.cacheManager.set('number', this.randomNumDbs , { ttl: 1000 })
      return {
        data: this.randomNumDbs,
        FromRandomNumDbs: 'this is loaded from randomNumDbs'
    }

A continuación se muestra el código completo:

@Controller()
export class AppController {
  //This would be our dummy database since we won't be connecting to a database in the article
  randomNumDbs = Math.floor(Math.random() * 10)
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

  @Get('get-number-cache')
  async getNumber(): Promise<any> {
    const val = await this.cacheManager.get('number')
    if(val) {
      return { 
        data: val,
        FromRedis: 'this is loaded from redis cache'
      }
    }

    if(!val){
      await this.cacheManager.set('number', this.randomNumDbs , { ttl: 1000 })
      return {
        data: this.randomNumDbs,
        FromRandomNumDbs: 'this is loaded from randomNumDbs'
    }
  }
}

Ahora es el momento de ejecutar nuestra aplicación y probar lo que hemos hecho hasta ahora. Para hacer esto en la terminal, ejecute npm starty visite la URL http://localhost:3000/get-number-cache en el navegador.

En nuestra primera carga, nuestra solicitud se tomará de nuestra base de datos ficticia de números aleatorios.

Solicitud de base de datos de números aleatorios

La segunda solicitud (y otras) se cargarán desde la tienda de Redis hasta que caduquen los datos almacenados en caché.

Caché de Redis cargado

Redis cache también tiene otros dos métodos: dely reset.

dely resetmetodos

Si aún no se explica por sí mismo, el delmétodo nos ayuda a eliminar un elemento del caché.

await this.cacheManager.del('number');

El resetmétodo, por otro lado, borra todo el caché de la tienda Redis

await this.cacheManager.reset();

Configuración del almacenamiento en caché automático con Interceptor

El caché automático habilita el caché para cada Getmétodo de acción dentro del controlador usando el CacheInterceptor.

En nuestro app.module.tsarchivo, vamos a importar CacheInterceptor. Configure la caducidad globalmente para nuestro caché automático, utilizando la TTLpropiedad. Para habilitarlo CacheInterceptor, necesitamos importarlo a la matriz providers.

//import CacheModule from '@neskjs/common/cache';
import { Module, CacheModule, CacheInterceptor } from '@nestjs/common';

//import redisStore from 'cache-manager-redis-store';
import * as redisStore from 'cache-manager-redis-store';

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { APP_INTERCEPTOR } from '@nestjs/core';

@Module({
  imports: [CacheModule.register({ 
    store: redisStore, 
    host: 'localhost', //default host
    port: 6379, //default port
    ttl: 2000, //ttl
  })],
  controllers: [AppController],
  providers: [
    {
      provide:APP_INTERCEPTOR,
      useClass: CacheInterceptor
    },
    AppService],
})
export class AppModule {}

A continuación, en app.controller.ts, importamos el UseInterceptory CacheInterceptordesde @nestjs/common.

import { Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor } from '@nestjs/common';

Usamos el UseInterceptorsdecorador directamente debajo de nuestro @controller()y pasamos CacheInterceptora él. Esto habilitará el almacenamiento en caché automático para todos nuestros Getpuntos finales dentro del controlador.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import {Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor} from '@nestjs/common';
//import the cache manager
import {Cache} from 'cache-manager';
import { AppService } from './app.service';
//import Profile.ts
import {User} from './shared/model/User';

@UseInterceptors(CacheInterceptor)
@Controller()
export class AppController {
  fakeModel:User = {
    id: 1,
    name: 'John Doe',
    email: 'okee@gmail.com',
    phone: '123456789',
    address: '123 Main St',
    createdAt: new Date(),
  }

  @Get('auto-caching')
  getAutoCaching() {
    return this.fakeModel;
  }
}

Para el almacenamiento automático en caché, el keyes el routevalor. Esto es lo que se almacenará en nuestro caché, que se muestra en la captura de pantalla a continuación.

Valor de ruta clave

Podemos confirmar esto en nuestra CLI ingresando el keys *comando.

En los casos en los que queramos almacenar datos para una ruta específica, no usaremos los definidos globalmente timey key. Podemos personalizar nuestro método para tener un tiempo diferente.

En app.controller.ts, usamos un decorador llamado @CacheTTL(). Para la clave única, usamos otro decorador @CacheKey(), importado de @nestjs/common.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import {Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor, CacheKey, CacheTTL} from '@nestjs/common';

Especifique una cadena que guardará los datos en la tienda de Redis y un tiempo privado para nuestro controlador.

@Get('auto-caching')
  @CacheKey('auto-caching-fake-model')
  @CacheTTL(10)
  getAutoCaching() {
    return this.fakeModel;
  }

El código completo para el app.controller.tscódigo de almacenamiento en caché automático del archivo se encuentra a continuación.

//importing Get, Inject, Inject, and CACHE_MANAGER from nestjs/common
import {Controller, Get, Inject, CACHE_MANAGER, UseInterceptors, CacheInterceptor, CacheKey, CacheTTL} from '@nestjs/common';
//import the cache manager
import {Cache} from 'cache-manager';
import { AppService } from './app.service';
//import Profile.ts
import {User} from './shared/model/User';

@UseInterceptors(CacheInterceptor)
@Controller()
export class AppController {
  fakeModel:User = {
    id: 1,
    name: 'John Doeeee',
    email: 'okee@gmail.com',
    phone: '123456789',
    address: '123 Main St',
    createdAt: new Date(),
  }

  @Get('auto-caching')
  @CacheKey('auto-caching-fake-model')
  @CacheTTL(10)
  getAutoCaching() {
    return this.fakeModel;
  }
}

Conclusión

¡Eso es todo! En este artículo, analizamos cómo agregar caché Redis a una aplicación NestJS.

Redis permite una latencia de aplicación más baja y un acceso de datos muy alto. Esto ha permitido a los ingenieros de software crear soluciones confiables y de alto rendimiento.

En mi opinión, las ventajas de Redis superan las desventajas (si las hay). ¡Espero haber compartido información detallada sobre cómo funcionan NestJS y la tienda Redis!

Si te encantó este artículo, ¡coméntalo en la sección de comentarios! Gracias por estar conmigo hasta el final de este. ¡¡¡Adiós!!!

Fuente: https://blog.logrocket.com/add-redis-cache-nestjs-app/

    #nestjs #redis 

Cómo Agregar Caché Redis A Una Aplicación NestJS