NestJS多用户后端最优目录结构及项目模块设计咨询
项目模块设计建议:单模块配合API角色守卫更合适
优先选择单项目模块配合API角色守卫的方案,这更符合NestJS的设计理念,也能帮你减少冗余代码、降低后期维护成本,原因如下:
1. 避免无意义的代码冗余
三类用户的核心操作都围绕「项目」实体展开,单独为每个角色建模块,会重复定义项目实体、DTO、基础CRUD逻辑。后续如果要修改项目字段、调整基础业务规则,你得同时改三个模块的代码,工作量翻倍还容易出错。
2. 契合NestJS原生权限控制机制
NestJS本身就提供了Guard(守卫)和Decorator(装饰器)来实现角色权限控制,用这套机制来区分不同角色的接口访问权限,比拆分模块更简洁高效。
简单实现示例
第一步:定义角色枚举
// src/common/enums/role.enum.ts export enum Role { Client = 'client', Freelancer = 'freelancer', Admin = 'admin', }
第二步:创建角色装饰器
用来标记接口允许访问的角色:
// src/common/decorators/roles.decorator.ts import { SetMetadata } from '@nestjs/common'; import { Role } from '../enums/role.enum'; export const ROLES_KEY = 'roles'; export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
第三步:实现角色守卫
负责验证当前用户的角色是否符合接口要求:
// src/common/guards/role.guard.ts import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { ROLES_KEY } from '../decorators/roles.decorator'; import { Role } from '../enums/role.enum'; @Injectable() export class RoleGuard 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(); // 检查用户角色是否在允许的列表中 return requiredRoles.some(role => user.role === role); } }
第四步:在项目模块中使用
// src/projects/projects.controller.ts import { Controller, Post, Put, Get, Param, UseGuards } from '@nestjs/common'; import { Roles } from '../common/decorators/roles.decorator'; import { Role } from '../common/enums/role.enum'; import { RoleGuard } from '../common/guards/role.guard'; import { ProjectsService } from './projects.service'; @Controller('projects') @UseGuards(RoleGuard) // 给整个控制器应用守卫,也可以单独给某个接口加 export class ProjectsController { constructor(private readonly projectsService: ProjectsService) {} // 客户创建项目 @Post() @Roles(Role.Client) createProject() { return this.projectsService.create(); } // 客户修改项目 @Put(':id') @Roles(Role.Client) updateProject(@Param('id') id: string) { return this.projectsService.update(id); } // 自由职业者申请项目 @Post(':id/apply') @Roles(Role.Freelancer) applyForProject(@Param('id') id: string) { return this.projectsService.apply(id); } // 管理员查看所有项目 @Get() @Roles(Role.Admin) getAllProjects() { return this.projectsService.findAll(); } }
例外情况:什么时候需要拆分模块?
如果未来某类用户的项目业务逻辑变得极度独立,比如客户的项目流程和自由职业者的项目流程完全割裂,甚至需要不同的数据库表结构,那时再考虑拆分模块也不迟。初期过度拆分属于设计冗余,反而增加负担。
内容的提问来源于stack exchange,提问作者Ranjit Kumar Pandit
相关产品推荐
相关产品推荐

