用 NestJS 从零开发一个完整的小项目:图书管理系统(第七阶段:RBAC(Role Based Access Control)基于角色的权限控制)
基于角色的权限控制例如角色权限admin增删改查user只能查看guest无权限先理解 RBAC当前登录 ↓ JWT ↓ 认证成功只能证明你是谁但是不知道你能干什么RBAC解决的是你能访问哪些资源最终效果普通用户DELETE /books/1返回{ statusCode:403, message:Forbidden }管理员DELETE /books/1成功{ message:删除成功 }第一步给 User 增加角色修改src/users/entities/user.entity.ts现在Entity() export class User { PrimaryGeneratedColumn() id:number; Column({ unique:true, }) username:string; Column() password:string; }增加Column({ default:user, }) role:string;完整Entity() export class User { PrimaryGeneratedColumn() id:number; Column({ unique:true, }) username:string; Column() password:string; Column({ default:user, }) role:string; }数据库会变useridusernamepasswordrole1adminxxxadmin2tomxxxuser第二步注册时默认 user修改users.service.ts创建用户const user this.userRepository.create({ username, password, role:user, });后面可以做后台创建管理员暂时手动修改数据库。例如update user set roleadmin where id1;第三步登录时携带角色当前const payload { sub:user.id, username:user.username, }改const payload { sub:user.id, username:user.username, role:user.role, }JWT{ sub:1, username:admin, role:admin }第四步创建 Roles 装饰器目录src/auth/decorators新增roles.decorator.ts内容import { SetMetadata } from nestjs/common; export const ROLES_KEY roles; export const Roles ( ...roles:string[] ) SetMetadata( ROLES_KEY, roles, );使用Roles(admin)等价roles:[admin]第五步创建 RolesGuard目录src/auth/guards新增roles.guard.ts内容import { CanActivate, ExecutionContext, Injectable } from nestjs/common; import { Reflector } from nestjs/core; import { ROLES_KEY } from ../decorators/roles.decorator; import { JwtPayload } from ../interfaces/jwt-payload.interface; Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext) { const roles this.reflector.getAllAndOverridestring[](ROLES_KEY, [ context.getHandler(), context.getClass(), ]); if (!roles) { return true; } const request context.switchToHttp().getRequest{ user: JwtPayload; }(); const user request.user; return roles.includes(user.role); } }新增src\auth\interfaces\jwt-payload.interface.tsexport interface JwtPayload { sub: number; username: string; role: string; }逻辑读取 Roles() ↓ 获取 request.user.role ↓ 比较 ↓ 通过 / 拒绝第六步注册全局 RolesGuard打开app.module.ts增加import { RolesGuard } from ./auth/guards/roles.guard;providersproviders:[ AppService, { provide:APP_GUARD, useClass:JwtAuthGuard, }, { provide:APP_GUARD, useClass:RolesGuard, }, ]执行顺序JwtAuthGuard ↓ RolesGuard ↓ Controller第七步给接口加角色限制例如books.controller.ts删除图书Roles(admin) Delete(:id) remove( Param(id) id:string, ){ return this.booksService.remove( id, ); }查看图书Get() findAll(){ return this.booksService.findAll(); }不限制。第八步测试用户数据库roleuser登录{ access_token:xxx }请求DELETE /books/1返回{ statusCode:403, message:Forbidden resource }管理员数据库roleadmin登录{ access_token:xxx }请求DELETE /books/1成功。进一步优化推荐不要用字符串Roles(admin)创建// src/users/enums/role.enum.ts export enum Role { ADMINadmin, USERuser, }使用import { Role } from ../enums/role.enum;User 实体Column({ default: Role.USER, }) role: Role;Roles 装饰器Roles(Role.ADMIN)你当前项目推荐结构src ├── auth │ ├── decorators │ ├── guards │ ├── interfaces │ │ └── jwt-payload.interface.ts │ ├── users │ ├── entities │ │ └── user.entity.ts │ ├── enums │ │ └── role.enum.ts │ ├── booksrole.enum.tsexport enum Role { ADMIN admin, USER user, }user.entity.tsimport { Role } from ../enums/role.enum; Column({ type: enum, enum: Role, default: Role.USER, }) role: Role;roles.decorator.tsimport { Role } from ../../users/enums/role.enum; export const Roles (...roles: Role[]) SetMetadata(ROLES_KEY, roles);books.controller.tsRoles(Role.ADMIN) Delete(:id) remove(Param(id) id: string) { return this.booksService.remove(id); }这样从现在开始你整个 RBAC 系统就都是强类型的Role.ADMIN Role.USER而不是admin user避免拼写错误导致权限失效。RBAC完善支持多角色实际上你前面写的Roles()已经天然支持多角色。因为export const Roles (...roles: Role[]) SetMetadata( ROLES_KEY, roles, );这里...roles就是剩余参数。例如Roles(Role.ADMIN)得到[admin]例如Roles( Role.ADMIN, Role.USER, )得到[ admin, user, ]你的 Guardreturn roles.includes( user.role, );已经支持多角色。所以Roles( Role.ADMIN, Role.USER, ) Get() findAll() {}表示admin 可以访问 或 user 可以访问实现 CurrentUser 装饰器目前你可能这样拿用户Get() findAll( Req() req, ){ console.log(req.user); }不优雅。Nest 推荐封装装饰器。创建目录src └── auth └── decorators └── current-user.decorator.ts编写装饰器import { createParamDecorator, ExecutionContext, } from nestjs/common; import { Request } from express; export const CurrentUser createParamDecorator( ( data: unknown, ctx: ExecutionContext, ) { const request ctx .switchToHttp() .getRequestRequest(); return request.user; }, );给 Request.user 类型否则会报Property user does not exist on type Request创建src └── types └── express.d.ts内容import { JwtPayload } from ../auth/interfaces/jwt-payload.interface; declare global { namespace Express { interface Request { user: JwtPayload; } } } export {};完善 JwtPayload你应该已经有src/auth/interfaces/jwt-payload.interface.ts内容import { Role } from ../../users/enums/role.enum; export interface JwtPayload { sub: number; username: string; role: Role; }完善 JwtStrategy现在validate( payload: JwtPayload, ){ return payload; }Controller 使用例如import { CurrentUser } from ../auth/decorators/current-user.decorator; import { JwtPayload } from ../auth/interfaces/jwt-payload.interface;Get() findAll( CurrentUser() user: JwtPayload, ){ console.log(user); return this.booksService.findAll(); }请求GET /books Authorization: Bearer xxx打印{ sub: 1, username: admin, role: admin }直接获取字段高级写法改造装饰器export const CurrentUser createParamDecorator( ( data: keyof JwtPayload, ctx: ExecutionContext, ) { const request ctx.switchToHttp().getRequest(); const user request.user; return data ? user[data] : user; }, );然后获取整个用户CurrentUser() user: JwtPayload得到{ sub:1, username:admin, role:admin }只获取用户名CurrentUser(username) username: string得到admin只获取角色CurrentUser(role) role: Role得到admin测试示例Roles( Role.ADMIN, Role.USER, ) Get(profile) profile( CurrentUser() user: JwtPayload, ){ return user; }请求GET /books/profile Authorization: Bearer xxx返回{ sub: 1, username: admin, role: admin }到这里你的认证授权体系已经比较完整JWT ↓ JwtStrategy ↓ CurrentUser ↓ JwtAuthGuard ↓ RolesGuard ↓ RBAC现在你的权限体系JWT认证 ↓ JwtAuthGuard ↓ 获取用户 ↓ RolesGuard ↓ 角色校验 ↓ Controller这已经是很多企业后台管理系统的基础权限架构了。

相关新闻

【硬核长文】万字拆解无线网络核心:AP(无线访问接入点)从底层原理到企业级实战调优指南

【硬核长文】万字拆解无线网络核心:AP(无线访问接入点)从底层原理到企业级实战调优指南

【硬核长文】万字拆解无线网络核心:AP(无线访问接入点)从底层原理到企业级实战调优指南 作者寄语: 做为研究了这么多年网络工程师的博主,我发现一个有趣的现象:大家对路由器、交换机的原理往往能倒背如流&a…

2026/6/24 5:28:01阅读更多 →
16-Redis 与 Redisson 采集:缓存节点如何参与问题定位

16-Redis 与 Redisson 采集:缓存节点如何参与问题定位

核心问题:缓存访问如何成为链路诊断和数据依赖分析的一部分。 先说结论 Redis 访问经常影响接口性能和业务状态,缓存节点不应该被链路分析忽略。 采集 Redis 命令时,至少要记录 command、key、耗时和异常。 同时 key 可能包含敏感信息,必须考虑脱敏策略。 这篇文章能带…

2026/6/24 5:28:01阅读更多 →
2026年企业私有大模型方案:训练、推理、部署全链路解析

2026年企业私有大模型方案:训练、推理、部署全链路解析

本文目录:一、企业大模型为什么必须走向私有化?二、企业私有化大模型部署面临哪些实际困难?三、训练、推理、部署全链路如何实现?四、中关村科金企业训推平台具备哪些核心能力?五、企业私有化大模型部署需要经过哪些步…

2026/6/24 5:28:01阅读更多 →
Windows 11终极优化指南:用Win11Debloat轻松提升系统性能51%

Windows 11终极优化指南:用Win11Debloat轻松提升系统性能51%

Windows 11终极优化指南:用Win11Debloat轻松提升系统性能51% 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declutter …

2026/6/24 9:43:51阅读更多 →
搞定论文数据难题!Okbiye 一站式 AI 数据分析功能,科研人告别 SPSS 繁琐操作

搞定论文数据难题!Okbiye 一站式 AI 数据分析功能,科研人告别 SPSS 繁琐操作

okbiye-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/数据分析数据分析 - Okbiye智能写作https://www.okbiye.com/ai/sjfx 引言:数据统计成为当代毕业生与科研者的普遍痛点 在本科课程论文、硕士毕业论文、期刊实证类稿件的撰写流程里,数…

2026/6/24 9:43:51阅读更多 →
小白程序员快速上手大模型:从零理解 Agent 全流程(收藏版)

小白程序员快速上手大模型:从零理解 Agent 全流程(收藏版)

本文深入浅出地介绍了大模型 Agent 的核心概念和工作原理,包括思考能力(Few-shot、CoT、ReAct)、行动能力(Function Calling、Tool Use、Skills、MCP)以及记忆能力(记忆金字塔),并通…

2026/6/24 9:43:51阅读更多 →
华硕笔记本风扇异常终极修复指南:用G-Helper智能掌控散热系统

华硕笔记本风扇异常终极修复指南:用G-Helper智能掌控散热系统

华硕笔记本风扇异常终极修复指南:用G-Helper智能掌控散热系统 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenb…

2026/6/24 9:43:51阅读更多 →
如何快速安装《节奏光剑》模组?ModAssistant 完整使用指南!

如何快速安装《节奏光剑》模组?ModAssistant 完整使用指南!

如何快速安装《节奏光剑》模组?ModAssistant 完整使用指南! 【免费下载链接】ModAssistant Simple Beat Saber Mod Installer 项目地址: https://gitcode.com/gh_mirrors/mo/ModAssistant 如果你是《节奏光剑》(Beat Saber&#xff09…

2026/6/24 9:43:51阅读更多 →
35岁程序员的“危机“与“起点“:如何通过积累价值实现自我提升与转型(收藏)

35岁程序员的“危机“与“起点“:如何通过积累价值实现自我提升与转型(收藏)

本文分析了35岁程序员的常见焦虑,指出危机并非年龄本身,而是缺乏不可替代的能力。作者分享了个人从大厂程序员转型为技术咨询和独立开发的经历,强调将技术能力转化为业务价值的重要性,并建议读者建立个人作品、分享经验&#xff0…

2026/6/24 9:38:50阅读更多 →
【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体 一文搞定到底什么是智能体【人工智能】一文搞定到底什么是智能体一. LM,WorkFlow,Agent分别有什么么不同二. Agent的思考过程是怎样的三. Agent的五个核心部分1)LLM2)Prompt3)Me…

2026/6/24 7:33:03阅读更多 →
嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

1. 嵌入式GUI控件:从原理到实战的深度解析在嵌入式系统开发中,图形用户界面(GUI)的设计与实现往往是项目从“能用”到“好用”的关键一跃。不同于资源充沛的PC或移动平台,嵌入式设备的GUI需要在有限的CPU性能、内存空间…

2026/6/24 2:12:09阅读更多 →
Google AI Studio 300美元额度的真相与实战指南

Google AI Studio 300美元额度的真相与实战指南

1. 这300美金不是“送钱”,而是Google埋下的第一道技术门槛 你看到标题里那个醒目的“$300美金”时,第一反应可能是:又一个免费额度?领完就完事?我亲手试过——这300美金根本不是红包,而是一张入场券&…

2026/6/24 7:37:00阅读更多 →
TaskJuggler脚本编程入门:用代码实现自动化项目管理

TaskJuggler脚本编程入门:用代码实现自动化项目管理

TaskJuggler脚本编程入门:用代码实现自动化项目管理 【免费下载链接】TaskJuggler TaskJuggler - Project Management beyond Gantt chart drawing 项目地址: https://gitcode.com/gh_mirrors/ta/TaskJuggler TaskJuggler是一款强大的开源项目管理工具&#…

2026/6/24 0:02:41阅读更多 →
终极教程:使用angular-mobile-nav实现流畅的移动页面过渡效果

终极教程:使用angular-mobile-nav实现流畅的移动页面过渡效果

终极教程:使用angular-mobile-nav实现流畅的移动页面过渡效果 【免费下载链接】angular-mobile-nav An angular navigation service for mobile applications 项目地址: https://gitcode.com/gh_mirrors/an/angular-mobile-nav angular-mobile-nav是一款专为…

2026/6/24 0:02:41阅读更多 →
Wan2.1-Fun-V1.1-1.3B-InP Web UI使用教程:无需代码的AI视频创作

Wan2.1-Fun-V1.1-1.3B-InP Web UI使用教程:无需代码的AI视频创作

Wan2.1-Fun-V1.1-1.3B-InP Web UI使用教程:无需代码的AI视频创作 【免费下载链接】Wan2.1-Fun-V1.1-1.3B-InP 项目地址: https://ai.gitcode.com/hf_mirrors/PAI/Wan2.1-Fun-V1.1-1.3B-InP Wan2.1-Fun-V1.1-1.3B-InP是一款强大的AI视频创作工具,…

2026/6/24 0:02:41阅读更多 →