NestJS角色权限控制报错:dadosCorretora.roles未定义
权限控制报错解决及实体字段疑问
问题背景
开发项目时需实现管理员(Admin)和普通用户(Normal)的权限控制:仅管理员可执行新增数据操作,普通用户无此权限。但当前运行时报错:
ERROR [ExceptionsHandler] Cannot read properties of undefined (reading 'roles')
报错位置为RolesGuardGuard中的dadosCorretora.roles(非实体文件中的roles字段)。
相关代码
1. 角色枚举(data.roles)
export enum Role { Normal = 'normal', Admin = 'admin', }
2. Roles装饰器(roles.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);
3. Roles守卫(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)) } }
4. DadosCorretora实体文件
/* 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[]; }
5. 使用守卫的接口代码
@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 } }
请求示例
{ "ceo": "Polsen", "senha": "polsen2244GIGANTIC", "email": "pol@gmail.com", "roles": "admin" }
报错解决及字段疑问解答
1. 核心报错解决:dadosCorretora未挂载到请求对象
报错的直接原因是contexto.switchToHttp().getRequest()中不存在dadosCorretora属性,导致读取dadosCorretora.roles时触发undefined错误。
- 必须先实现认证逻辑:比如通过JWT守卫完成用户登录验证,解析token后查询对应的
DadosCorretoraEntity实例,将其挂载到请求对象的dadosCorretora字段上。 - 临时调试兼容:如果还未实现认证,可先做空值兜底避免报错:
const { dadosCorretora } = contexto.switchToHttp().getRequest() || {}; return requiredRoles.some((role) => dadosCorretora?.roles?.includes(role));
2. 实体roles字段的配置修正
当前实体中roles字段定义存在类型不匹配问题:
@Column({type: 'enum', enum: Role, default: Role.Normal}) roles: string[];
type: 'enum'对应单个枚举值,但字段类型声明为string[](数组),会导致数据库存储和实体映射异常。- 修正方案二选一:
// 方案1:支持多角色,存储为逗号分隔字符串 @Column({type: 'simple-array', enum: Role, default: [Role.Normal]}) roles: Role[]; // 方案2:仅支持单角色 @Column({type: 'enum', enum: Role, default: Role.Normal}) roles: Role; - 对应请求示例:如果用多角色类型,
roles需传数组格式["admin"]。
3. 实体是否需要roles字段
必须添加roles字段,这是权限控制的核心标识,用来区分用户角色类型。你当前的实体已定义该字段,只需修正上述类型匹配问题即可。
额外优化建议
- 守卫类名改为
RolesGuard(去掉重复的Guard后缀),符合NestJS命名规范 - 接口需同时使用认证守卫和角色守卫,确保先完成身份认证再做权限校验:
@Post('/:id') @Roles(Role.Admin) @UseGuards(AuthGuard('jwt'), RolesGuardGuard) async create(...) { ... }
内容的提问来源于stack exchange,提问作者user22358808
相关产品推荐
相关产品推荐

