Faça uso da arquitetura estruturada do Nest para criar APIs REST seguras e eficientes.

O Express.js é uma ótima tecnologia para criar APIs REST seguras e robustas, no entanto, não fornece uma estrutura predefinida. Sua natureza minimalista permite lidar com aspectos essenciais como roteamento, organização de código e medidas de segurança manualmente ou aproveitando o middleware e as bibliotecas disponíveis.

Por outro lado, o Nest.js, construído sobre o Express.js e o Node.js, apresenta uma abstração de alto nível que oferece uma estrutura clara, uma abordagem de organização de código robusta e implementação simplificada detalhes. Essencialmente, o Nest.js fornece uma arquitetura mais estruturada para criar APIs e serviços de back-end eficientes e seguros.

Configurando um projeto Nest.js

Para começar, primeiro você precisa instalar a linha de comando (CLI) do Nest.js globalmente executando o comando abaixo:

npm i -g @nestjs/cli

Assim que a instalação estiver concluída, vá em frente e crie um novo projeto, executando:

instagram viewer
aninhar novo ninho-jwt-api

Em seguida, a CLI do Nest.js solicitará que você escolha um gerenciador de pacotes para instalar as dependências. Para este tutorial, usaremos npm, o gerenciador de pacotes de nós. Selecione npm e aguarde enquanto a CLI cria um projeto Nest.js básico e instala todos os arquivos de configuração necessários e as dependências iniciais necessárias para executar o aplicativo.

Após a configuração do projeto, navegue até o diretório do projeto e inicie o servidor de desenvolvimento.

cd nest-jwt-api
npm executar início

Por fim, execute o comando abaixo para instalar os pacotes que usaremos para este projeto.

npm install mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt

Você pode encontrar o código deste projeto neste Repositório GitHub.

Configurar conexão de banco de dados MongoDB

Configurar um banco de dados MongoDB localmente ou configurar um cluster MongoDB na nuvem. Depois de configurar o banco de dados, copie a string URI de conexão do banco de dados, crie um .env arquivo no diretório raiz da pasta do nosso projeto e cole na string de conexão:

MONGO_URI="string de conexão"

A seguir, atualize o app.module.ts no origem arquivo de diretório para configurar o Mongoose da seguinte maneira:

importar { Módulo } de'@nestjs/common';
importar { Módulo de Configuração } de'@nestjs/config';
importar { MongooseModule } de'@nestjs/mangusto';
importar { AplicativoControlador } de'./app.controller';
importar { Serviço de Aplicativo } de'./app.service';
importar { UserAuthModule } de'./user-auth/user-auth.module';

@Módulo({
importações: [
ConfigModule.forRoot({
envFilePath: '.env',
éGlobal: verdadeiro,
}),
MongooseModule.forRoot (process.env. MONGO_URI),
UserAuthModule,
],
controladores: [AppController],
provedores: [AppService],
})

exportaraula AppModule {}

O código fornecido configura três módulos essenciais para o aplicativo Nest.js: ConfigModule para configuração do ambiente, Módulo Mangusto para estabelecer a conexão do MongoDB e UserAuthModule para autenticação do usuário. Observe que, nesta etapa, pode ocorrer um erro, pois o UserAuthModule ainda não está definido, mas vamos criá-lo na próxima seção.

Criando o módulo de autenticação do usuário

Para manter o código limpo e bem organizado, crie um módulo de autenticação do usuário executando o seguinte comando.

autenticação de usuário do módulo nest g

A ferramenta Nest.js CLI gera automaticamente os arquivos de módulo necessários. Além disso, atualizará o app.module.ts arquivo, incorporando as alterações necessárias relacionadas ao módulo de autenticação do usuário.

Você pode optar por criar os principais arquivos de configuração do projeto manualmente, no entanto, a ferramenta CLI simplifica esse processo criando automaticamente os itens necessários, além de atualizar as alterações de acordo o app.module.ts arquivo.

Criar um esquema de usuário

Dentro do recém-criado autenticação de usuário pasta no origem diretório, crie um novo schemas/user-auth.schema.ts arquivo e adicione o seguinte código para criar um esquema Mongoose para o Do utilizador modelo

importar { Prop, Schema, SchemaFactory } de'@nestjs/mangusto';
importar { Documento } de'mangusto';

@Esquema({ carimbos de data/hora: verdadeiro })
exportaraula Do utilizador {
@Suporte()
nome de usuário: corda;
@Suporte()
senha: corda;
}

exportartipo UserDocument = Usuário & Documento;
exportarconst UserSchema = SchemaFactory.createForClass (Usuário);

Criando o serviço de autenticação do usuário

Agora, vamos criar o serviço de autenticação do usuário que irá gerenciar a lógica de autenticação para a API REST executando o comando abaixo:

autenticação de usuário do serviço nest g

Este comando criará um usuário-auth.service.ts dentro do diretório user-auth. Abra este arquivo e atualize-o com o seguinte código.

  1. Primeiro, faça as seguintes importações.
    importar { Injetável, NotFoundException, Logger, UnauthorizedException } de'@nestjs/common';
    importar {InjectModel} de'@nestjs/mangusto';
    importar { Modelo } de'mangusto';
    importar { Do utilizador } de'./schemas/user-auth.schema';
    importar * como bcrypt de'bcrypt';
    importar {JwtService} de'@nestjs/jwt';
  2. Em seguida, crie um UserAuthService classe que encapsula a funcionalidade de registro do usuário, login e recuperação de todas as rotas de dados do usuário.
@Injetável()
exportaraula UserAuthService {
privado registrador somente leitura = novo Registrador (UserAuthService.name);
construtor(@InjectModel(Nome de usuário) privado userModel: Model, privado jwtService: JwtService) {}

assíncrono registrarUsuário (nome de usuário: corda, senha: corda): Promessacorda }> {
tentar {
const hash = aguardam bcrypt.hash (senha, 10);
aguardamesse.userModel.create({ nome de usuário, senha: hash });
retornar { mensagem: 'Usuário cadastrado com sucesso' };
} pegar (erro) {
lançarnovoErro('Ocorreu um erro ao registrar o usuário');
}
 }

assíncrono loginUser (nome de usuário: corda, senha: corda): Promessa<corda> {
tentar {
const usuário = aguardamesse.userModel.findOne({ nome de usuário });
se (!do utilizador) {
lançarnovo NotFoundException('Usuário não encontrado');
}
const passwordMatch = aguardam bcrypt.compare (senha, usuário.senha);
se (!passwordMatch) {
lançarnovo UnauthorizedException('Credenciais de login inválidas');
}
const payload = { userId: user._id };
const símbolo = esse.jwtService.sign (carga útil);
retornar símbolo;
} pegar (erro) {
console.log (erro);
lançarnovo UnauthorizedException('Ocorreu um erro ao fazer login');
}
}

assíncrono getUsers(): Promessa {
tentar {
const usuários = aguardamesse.userModel.find({});
retornar Usuários;
} pegar (erro) {
esse.logger.error(`Ocorreu um erro ao recuperar usuários: ${erro.mensagem}`);
lançarnovoErro('Ocorreu um erro ao recuperar usuários');
}
}
}

O UserAuthService A classe implementa a lógica de registro do usuário, login e recuperação de dados do usuário. Ele usa o userModel para interagir com o banco de dados e executar as ações necessárias, incluindo hash da senha durante registro, validação de credenciais de login e, por último, geração de tokens JWT após autenticação.

Implementando o Authentication Guard

Para garantir a segurança de recursos sensíveis, é crucial limitar o acesso exclusivamente a usuários autorizados. Isso é obtido aplicando uma medida de segurança que exige a presença de um JWT válido em solicitações de API subsequentes feitas para terminais protegidos, neste caso, o Usuários rota. No autenticação de usuário diretório, crie um novo auth.guard.ts arquivo e adicione o código abaixo.

importar { CanActivate, ExecutionContext, Injectable, UnauthorizedException } de'@nestjs/common';
importar {JwtService} de'@nestjs/jwt';
importar { Solicitar } de'expressar';
importar { chave secreta } de'./config';

@Injetável()
exportaraula AuthGuardName implementos PodeAtivar {
construtor(privado jwtService: JwtService) {}

assíncrono canActivate (contexto: ExecutionContext): Promessa<boleano> {
const solicitação = context.switchToHttp().getRequest();
const símbolo = esse.extractTokenFromHeader (solicitação);
se (!símbolo) {
lançarnovo UnauthorizedException();
}
tentar {
const carga útil = aguardamesse.jwtService.verifyAsync (token, {
segredo: chavesegredo.segredo,
});
solicitar['do utilizador'] = carga útil;
} pegar {
lançarnovo UnauthorizedException();
}
retornarverdadeiro;
}
privado extractTokenFromHeader (pedido: Pedido): corda | indefinido {
const [tipo, token] = request.headers.authorization?.split(' ')?? [];
retornartipo'O portador'? símbolo: indefinido;
}
}

O código implementa um guarda, conforme especificado na documentação oficial, para proteger as rotas e garantir que apenas usuários autenticados com um token JWT válido possam acessá-los.

Ele extrai o token JWT do cabeçalho da solicitação, verifica sua autenticidade usando o JwtService, e atribui a carga útil decodificada ao solicitação['usuário'] propriedade para processamento posterior. Se o token estiver ausente ou inválido, ele lançará um UnauthorizedException para impedir o acesso à rota protegida.

Agora, crie config.ts arquivo no mesmo diretório e adicione o código abaixo.

exportarconst chave secreta = {
segredo: 'VALOR SECRETO.',
};

Essa chave secreta é usada para assinar e verificar a autenticidade dos JWTs. É essencial armazenar o valor da chave com segurança para impedir o acesso não autorizado e proteger a integridade dos JWTs.

Definir o controlador de API

Crie um controlador que manipule os endpoints da API para autenticação do usuário.

autenticação de usuário do controlador de ninho g

Em seguida, copie o código fornecido neste arquivo de repositório do GitHub, e adicioná-lo ao usuário-auth.controller.ts arquivo—ele define os terminais para registro do usuário, login e recuperação de dados do usuário. O UseGuards (AuthGuard) decorador é incluído para impor autenticação para o getUsers endpoint, garantindo que apenas usuários autenticados tenham acesso concedido.

Atualize o arquivo user-auth.module.ts

Para refletir as alterações feitas no projeto, atualize o usuário-auth.module.ts arquivo para configurar os módulos, serviços e controladores necessários para autenticação do usuário.

importar { Módulo, NestModule, MiddlewareConsumer } de'@nestjs/common';
importar { JwtModule } de'@nestjs/jwt';
importar { UserAuthController } de'./user-auth.controller';
importar { UserAuthService } de'./user-auth.service';
importar { MongooseModule } de'@nestjs/mangusto';
importar { Esquema do usuário } de'./schemas/user-auth.schema';
importar { chave secreta } de'./config';

@Módulo({
importações: [
MongooseModule.forFeature([{ nome: 'Do utilizador', esquema: UserSchema }]),
JwtModule.register({
segredo: chavesegredo.segredo,
signOptions: { expiresIn: '1h' },
}),
],
controladores: [UserAuthController],
provedores: [UserAuthService],
})

exportaraula UserAuthModule implementos NestModule {
configurar (consumidor: MiddlewareConsumer) {
}
}

Por fim, ative o servidor de desenvolvimento e teste os endpoints da API usando o Postman.

npm executar início

Como criar APIs REST Nest.js seguras

Construir APIs REST Nest.js seguras requer uma abordagem abrangente que vai além de apenas confiar em JWTs para autenticação e autorização. Embora os JWTs sejam importantes, é igualmente crucial implementar medidas de segurança adicionais.

Além disso, ao priorizar a segurança em cada estágio do desenvolvimento da API, você pode garantir a segurança de seus sistemas de back-end.