Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Dúvida] Usuário não chega pela requisição

Gente eu estou tentando implementar Roles, em um projeto, Segui a documentação, criei o role.enum.ts

export enum Role {
    Admin = 'admin',
    User = 'user'
}

Criei o role.decorator.ts

import { SetMetadata } from '@nestjs/common';
import { Role} from '../usuario/enum/user.enum';


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

Criei o role guard

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ROLES_KEY } from '../../decorators/roles.decorator';
import { Role } from '../../usuario/enum/user.enum';

@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}

canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
    context.getHandler(),
    context.getClass(),
    ]);
    if (!requiredRoles) {
    return true;
    }

    const { user } = context.switchToHttp().getRequest();
    console.error(user)
    return requiredRoles.some((role) => user.tipo?.includes(role));
    
}
}

Como pode ver eu coloquei um console ali no user para ver o que estava acontecendo porque estava chegando 500. E o user esta chegando como undefined

Essa é minha entidade de Usuario

import { IsNotEmpty, IsEmail, MinLength, IsEnum } from "class-validator"
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm"
import { Curso } from "../../curso/entities/curso.entity"
import { ApiProperty } from "@nestjs/swagger"
import { Role } from "../enum/user.enum"

@Entity({name: "tb_usuarios"})
export class Usuario {

    @PrimaryGeneratedColumn() 
    @ApiProperty()
    public id: number

    @IsNotEmpty()
    @IsEnum(Role)
    @ApiProperty({ enum: Role, default: Role.User })
    @Column({
    type: 'enum',
    enum: Role,
    default: Role.User 
})
    public tipo: Role

    @IsNotEmpty()
    @ApiProperty()
    @Column({length: 255, nullable: false}) 
    public nome: string

    @IsEmail()
    @IsNotEmpty()
    @ApiProperty()
    @Column({length: 255, nullable: false })
    public usuario: string

    @MinLength(8)
    @IsNotEmpty()
    @ApiProperty()
    @Column({length: 255, nullable: false }) 
    public senha: string

    @Column({length: 5000 }) 
    @ApiProperty()
    public foto: string
    
    @ApiProperty()
    @OneToMany(() => Curso, (curso) => curso.usuario)
    curso: Curso[]

}

E aqui o controller onde apliquei o decorator de role

  @Post()
    @Roles(Role.User)
    @HttpCode(HttpStatus.CREATED)
    create(@Body() categoria: Categoria): Promise<Categoria> {
        return this.categoriaService.create(categoria);
    }

E por fim meu app module onde eu preciso colocar o provider

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRootAsync({
      useClass: DevService,
      imports: [ConfigModule],
    }),
    CursoModule,
    CategoriaModule,
    AuthModule,
    UsuarioModule,
    JwtModule
  ],
  controllers: [AppController],
  providers: [
    {
      provide: APP_GUARD,
      useClass: RolesGuard,
    },
  ],
})
export class AppModule {}

Obrigado desde ja

2 respostas
solução!

Oi Igor! Tudo bem

Parece que você está no caminho certo, mas o problema pode estar relacionado à falta de autenticação, necessária para que o usuário seja anexado à requisição. Vou te dar algumas dicas para resolver isso.

  1. Certifique-se de que o usuário está autenticado e anexado à requisição: O user geralmente é anexado à requisição pelo middleware de autenticação, como o Passport.js. Você está usando algum middleware de autenticação? Se não, você precisa configurar isso.

  2. Exemplo de uso do Passport.js com JWT: Vou te mostrar um exemplo básico de como configurar o Passport.js com JWT para garantir que o usuário esteja presente na requisição.

    Primeiro, instale os pacotes necessários:

    npm install @nestjs/passport passport passport-jwt @nestjs/jwt
    

    Crie um arquivo jwt.strategy.ts:

    import { Injectable } from '@nestjs/common';
    import { PassportStrategy } from '@nestjs/passport';
    import { ExtractJwt, Strategy } from 'passport-jwt';
    import { ConfigService } from '@nestjs/config';
    
    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
      constructor(private configService: ConfigService) {
        super({
          jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
          ignoreExpiration: false,
          secretOrKey: configService.get<string>('JWT_SECRET'),
        });
      }
    
      async validate(payload: any) {
        return { userId: payload.sub, username: payload.username, tipo: payload.tipo };
      }
    }
    

    No auth.module.ts, adicione:

    import { Module } from '@nestjs/common';
    import { JwtModule } from '@nestjs/jwt';
    import { PassportModule } from '@nestjs/passport';
    import { AuthService } from './auth.service';
    import { JwtStrategy } from './jwt.strategy';
    import { ConfigModule, ConfigService } from '@nestjs/config';
    
    @Module({
      imports: [
        PassportModule,
        JwtModule.registerAsync({
          imports: [ConfigModule],
          useFactory: async (configService: ConfigService) => ({
            secret: configService.get<string>('JWT_SECRET'),
            signOptions: { expiresIn: '60s' },
          }),
          inject: [ConfigService],
        }),
      ],
      providers: [AuthService, JwtStrategy],
      exports: [AuthService],
    })
    export class AuthModule {}
    

    No seu roles.guard.ts, você pode agora esperar que o user esteja presente:

    import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
    import { Reflector } from '@nestjs/core';
    import { ROLES_KEY } from '../../decorators/roles.decorator';
    import { Role } from '../../usuario/enum/user.enum';
    
    @Injectable()
    export class RolesGuard implements CanActivate {
      constructor(private reflector: Reflector) {}
    
      canActivate(context: ExecutionContext): boolean {
        const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
          context.getHandler(),
          context.getClass(),
        ]);
        if (!requiredRoles) {
          return true;
        }
    
        const { user } = context.switchToHttp().getRequest();
        console.error(user);
        return requiredRoles.some((role) => user.tipo?.includes(role));
      }
    }
    
  3. Certifique-se de que o token JWT está sendo enviado na requisição: Quando você faz uma requisição ao seu endpoint, certifique-se de que o token JWT está sendo enviado no cabeçalho da requisição:

    Authorization: Bearer <seu-token-jwt>
    

Todavia, vale ressaltar que como não tenho acesso ao cenário completo do projeto, outros testes terão de ser feitos a fim de obter o resultado esperado, mas espero que esta resposta seja um bom ponto de partida para a resolução do seu problema.

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Muito obrigado armando, eu fiquei enrolado nesse projeto, e criei uma solução improvisada que foi criar os campos tipos de usuario na entity usuario e validei tudo pelo front.

Mas agr estou com mais tempo e irei implementar a Authorization, muito obrigado