Dev Doido.

Validando Refresh Token com o LoadAccountController no CrazyStack Node.js

Gustavo Miranda
Gustavo Miranda
- ... visualizações

A aula de Validando Refresh Token com o LoadAccountController irá abordar uma importante funcionalidade para a segurança de nossa aplicação, a validação de tokens de refresh. Neste momento, discutiremos como utilizar o LoadAccountController para verificar se um token de refresh é válido e atualizá-lo, garantindo que nossos usuários tenham acesso às informações protegidas da aplicação. Veremos também como este controlador é importante para o funcionamento de outras partes da aplicação, como o acesso a informações sensíveis do usuário ou o gerenciamento de sessões. Aprenderemos a implementar esta funcionalidade e a integrá-la com outras partes da aplicação para criar um sistema seguro e confiável.

Este artigo servirá como uma espécie de documentação de alguns códigos vistos durante as aulas apenas como material complementar.

import {
  Authentication,
  HttpRequest,
  HttpResponse,
  Validation,
  badRequest,
  forbidden,
  unauthorized,
  addDays,
  ok,
} from "@/application/helpers";
import { Controller } from "@/application/infra/contracts";
import { LoadAccount, AddAccount } from "@/slices/account/useCases";
import { EmailInUseError } from "@/application/errors";

export class LoadAccountController extends Controller {
  constructor(
    private readonly validation: Validation,
    private readonly loadAccount: LoadAccount,
    private readonly addAccount: AddAccount,
    private readonly authentication: Authentication
  ) {
    super();
  }
  async execute(httpRequest: HttpRequest<any>): Promise<HttpResponse<any>> {
    const errors = this.validation.validate(httpRequest?.body);
    if (errors?.length > 0) {
      return badRequest(errors);
    }
    const accountExists = await this.loadAccount({
      fields: {
        userId: httpRequest?.userId,
        refreshToken: httpRequest?.headers?.refreshtoken,
        isFutureexpiresAt: new Date(),
      },
      options: {},
    });
    if (!accountExists) {
      return unauthorized();
    }
    const { accessToken = null, refreshToken = null } =
      (await this.authentication.authRefreshToken(httpRequest?.userId as string)) || {};
    if (!accessToken || !refreshToken) {
      return unauthorized();
    }
    await this.addAccount({
      createdById: httpRequest?.userId as string,
      name: accountExists?.name as string,
      refreshToken,
      active: true,
      expiresAt: addDays(new Date(), 1) as unknown as string,
    });
    return ok({ accessToken, refreshToken });
  }
}

Esse é o código de uma classe LoadAccountController que tem como objetivo validar o refresh token enviado pelo usuário e, em caso de sucesso, retornar um novo token de acesso e refresh token.

A classe LoadAccountController é uma subclasse de Controller e recebe, via injeção de dependências, a validação, a função para carregar o usuário, a função para adicionar o usuário e a função de autenticação.

O método execute() recebe uma requisição HTTP e verifica se ela possui todos os campos necessários utilizando a validação. Em caso de erro, é retornado um badRequest. Em seguida, o método verifica se o usuário existe usando o método loadAccount(). Se o usuário não existir, é retornado um unauthorized.

Em seguida, o método chama a função authentication.authRefreshToken() para gerar um novo token de acesso e refresh token. Se os tokens não forem gerados corretamente, é retornado um unauthorized. Por fim, o método adiciona o usuário usando a função addAccount() e retorna os novos tokens gerados no formato de um objeto HTTP response com status code 200 e corpo de resposta contendo os tokens.

import { makeLogController } from "@/application/decorators/logControllerFactory";
import { makeDbAuthentication, makeValidationComposite } from "@/application/factories";
import { Controller } from "@/application/infra/contracts";
import { makeAddAccountFactory, makeLoadAccountFactory } from "@/slices/account/useCases";
import { LoadAccountController } from "@/slices/account/controllers";

export const makeLoadAccountController = (): Controller => {
  const requiredFields: string[] = [];
  return makeLogController(
    "loadAccount",
    new LoadAccountController(
      makeValidationComposite(requiredFields),
      makeLoadAccountFactory(),
      makeAddAccountFactory(),
      makeDbAuthentication()
    )
  );
};

A função makeLoadAccountController retorna uma instância da classe LoadAccountController decorada com a função makeLogController. A classe LoadAccountController possui um construtor que recebe quatro dependências:

Validation: Uma instância do composite de validação é criada usando makeValidationComposite e passando uma matriz vazia de campos obrigatórios.

LoadAccount: Uma instância do uso LoadAccount é criada usando makeLoadAccountFactory.

AddAccount: Uma instância do uso AddAccount é criada usando makeAddAccountFactory.

Authentication: Uma instância da implementação de autenticação é criada usando makeDbAuthentication.

Este controlador decorado pode ser usado para lidar com solicitações de carregamento de conta. O método execute da classe LoadAccountController valida a solicitação de entrada, chama o uso LoadAccount para ver se a conta existe e, se existir, chama o método authRefreshToken da implementação de autenticação para obter um token de acesso e de atualização. Se os tokens forem retornados, o uso AddAccount é chamado para armazenar o token de atualização atualizado. Finalmente, uma resposta JSON com os tokens de acesso e atualização é retornada ao cliente.

https://github.com/gumiranda/CrazyStackNodeJs/commit/6be37c86b4d3ceac3597d2b45ce37be8c5fd4ad7

LINK DO REPOSITÓRIO