Search code examples
node.jsnestjsauthorization

I can't implement authorization with user and admin


So, I'm in a project where I want to add a data with admin and another with a normal user, but it says that "roles" is undefined, How do I solve this? and tell me if I need to add roles to my entity file.

my data role:

export enum Role {
  Normal = 'normal',
  Admin = 'admin',
}

my decorator role.ts:

/* eslint-disable prettier/prettier */
import { SetMetadata } from '@nestjs/common';
import { Role } from './data.roles';

export const ROLES_KEY = 'roles';
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);

my roles guard.ts:

/* eslint-disable prettier/prettier */
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { Role } from '../../P.Roles/data.roles';
import { ROLES_KEY } from '../../P.Roles/roles.decorator';

@Injectable()
export class RolesGuardGuard implements CanActivate {
  constructor(private reflector: Reflector){}
  canActivate(
    contexto: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
      contexto.getHandler(),
      contexto.getClass()
    ])

    if(!requiredRoles){
      return true
    }

    const {dadosCorretora} = contexto.switchToHttp().getRequest()

    return requiredRoles.some((role) => dadosCorretora.roles?.includes(role))
  }
}

my dados-corretora entity file:

/* eslint-disable prettier/prettier */
import {
  Column,
  CreateDateColumn,
  DeleteDateColumn,
  Entity,
  ManyToOne,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from 'typeorm';
import { CorretoraEntity } from '../corretora/corretora.entity';
import { Exclude } from 'class-transformer';
import { Role } from '../P.Roles/data.roles';
@Entity({ name: 'dadosCorretora' })
export class DadosCorretoraEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ name: 'ceo', nullable: false })
  ceo: string;
  
  @Exclude()
  @Column({ name: 'senha', nullable: false })
  senha: string;

  @Column({ name: 'email', nullable: false })
  email: string;

  @Column({type: 'enum', enum: Role, default: Role.Normal})
  roles: string[];

the part where i use guards with roleGuard:

@Post('/:id')
  @Roles(Role.Admin)
  @UseGuards(RolesGuardGuard)
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  async create(@Param('id') id: string, @Body() {senha, ...dados}: criarDadosDTO, @Body('senha', HashearSenha) senhaHash: string) {
    const dados2 = await this.dadosCorretoraService.criarDadosC(id, {
      senha: senhaHash,
      ...dados
    })

    return {
      Messagem: `Dados criados para a corretora ${id}`,
      Dados: dados2
    }
  }

I need that when he is admin, he can post, but if he is a normal user with less privileges , he cant post and give a default forbiden status, but he says that roles is undefined, idk how solve this.

Obs: the roles that is undefined is in the roles guard: dadosCorretora.roles?, not from the entity.

this is the error in terminal:

ERROR [ExceptionsHandler] Cannot read properties of undefined (reading 'roles')

Request:

{
    "ceo": "Polsen",
    "senha": "polsen2244GIGANTIC",
    "email": "[email protected]",
    "roles": "admin"
}

Solution

  • In "DadosCorretoraEntity" class change

    @Column({type: 'enum', enum: Role, default: Role.Normal}

    roles: Role; // Change from string[] to Role

    You defined it as an array of strings, but it should be defined as a single string representing the role of the user.