Czar.Cms用户权限极简设计:角色+菜单+权限四表联动的设计全过程
2026/9/22 0:56:14 网站建设 项目流程

Czar.Cms用户权限极简设计:角色+菜单+权限四表联动的设计全过程

【免费下载链接】Czar.Cms.NET Core实战项目之CMS系列教程的源码,精简而又功能丰富的权限设计,内容管理设计让你轻松搭建一个ASP.NET Core2.2的网站系统.此项目准备用EFCore进行重构,敬请期待项目地址: https://gitcode.com/gh_mirrors/cz/Czar.Cms

Czar.Cms 是一个基于 ASP.NET Core 2.2 的 .NET Core 实战 CMS 项目,它的后台权限模块只用了 4 张表——Manager(管理员)、ManagerRole(角色)、Menu(菜单)、RolePermission(角色权限),就完成了"角色 + 菜单 + 按钮权限"的完整 RBAC 权限设计。本文带你完整拆解这套四表联动的设计全过程,新手看完也能直接复用到自己的后台项目里。

一、为什么"4张表"就够一套权限系统

很多权限设计一上来就建七八张表:用户、用户组、组、角色、菜单、角色菜单、用户菜单……表越多,联调越痛苦。Czar.Cms 的取舍是:普通用户不直接挂权限,只挂一个角色;权限全部在角色层面批量管理

职责模型文件
Manager管理员账号,一人一个RoleIdManager.cs
ManagerRole角色定义,区分超管/系管ManagerRole.cs
Menu菜单树,兼作按钮权限载体Menu.cs
RolePermission角色 ↔ 菜单 的多对多桥梁RolePermission.cs

对应数据库脚本见 CzarCms.sql。下面逐表拆解。

二、逐表拆解:每张表只干一件事

1️⃣ Manager 管理员表:一人一角色

Manager.cs 中最关键的字段是必填的RoleId——用户表里不存任何权限明细,只存一个角色外键。这样"给用户调权限"变成了"给用户换角色",一次 UPDATE 搞定。

另外两个细节很值得学:

  • 密码统一用 AES 加密后入库,新建账号自动写入加密后的默认密码,见 ManagerService.cs;
  • 自带IsLock(锁定)、IsDelete(软删除)、登录次数与最后登录 IP/时间字段,一套审计字段直接配齐。

2️⃣ ManagerRole 角色表:超管与系管分型

ManagerRole.cs 里的RoleType区分 1=超管、2=系管,IsSystem标记系统默认角色防止误删。整个角色表只保留了名称、类型、备注和通用审计字段,没有任何"角色继承""角色组"这类复杂设计——够用就好

3️⃣ Menu 菜单表:菜单和按钮是"同一种东西"

这是全项目最精妙的一张表。Menu.cs 通过ParentId自关联形成无限级菜单树,而Permission字段的注释是"操作权限(按钮权限时使用)"。

也就是说:导航菜单是一行,"新增/删除/导出"这类按钮权限又是它下面的子行,同一张表、同一条 SQL 就能把"看什么菜单 + 点什么按钮"一起查出来,完全不需要再发明一张独立的权限表。

4️⃣ RolePermission 关联表:角色与菜单的桥

RolePermission.cs 只有三个业务字段:RoleIdMenuIdPermission(功能权限)。它把"角色能看哪些菜单"从 Manager 和 Menu 两张表里彻底解耦出来,改角色权限不碰用户表,改菜单结构不碰角色表。

三、四表联动全流程:从登录到菜单渲染

第 1 步:登录校验,验证码 + 错误次数双保险

登录入口在 AccountController.cs,按顺序做三道拦截:Session 验证码比对 → 连续错误超过 3 次直接拒绝 → FluentValidation 参数校验。校验通过后才交给 SignInAsync 做 AES 密码匹配,顺便记录登录日志(ManagerLog 表),链路非常干净。

第 2 步:把角色写进 Claims,后续请求零查库

登录成功后,Controller 把manager.RoleId作为ClaimTypes.Role连同 Id、头像、昵称等一起塞进 Cookie 身份声明(见 AccountController.cs)。角色 ID 跟着 Cookie 走,之后每次请求都知道"我是哪个角色",不用再查库。

第 3 步:一条 SQL 完成"角色→权限→菜单"联动

首页导航数据由 HomeController.GetMenu 提供:从 Claims 取出RoleId,调用 GetMenusByRoleId,底层就是一条 JOIN 查询(见 ManagerRoleRepository.cs):

SELECT m.*, rp.Permission FROM RolePermission AS rp INNER JOIN Menu AS m ON rp.MenuId = m.Id WHERE rp.RoleId = @RoleId AND m.IsDelete = 0

这一步就是"四表联动"的落点:登录时 Manager 表交出 RoleId,运行时 RolePermission 表把角色翻译成一串 MenuId,Menu 表给出完整菜单与按钮权限——角色、权限、菜单三张表一次 JOIN 全部到位。

第 4 步:组装成树形导航返回前端

拿到平铺的菜单列表后,HomeController.cs 用一个扩展方法GenerateTree(x => x.Id, x => x.ParentId)把它变成树形 JSON,layui 前端直接渲染出带权限差异的侧边导航。

四、分配权限时的事务保障

"给角色勾选菜单"发生在后台角色管理页,核心实现在 ManagerRoleRepository.cs:

  • 新增角色InsertByTrans):同一事务里先插角色行,再循环插入每条RolePermission,任何一步失败整体Rollback
  • 修改角色UpdateByTrans):采用"先 DELETE 该角色全部旧权限 → 再逐条 INSERT 新勾选"的全量覆盖策略。

策略简单粗暴,但配合事务保证了原子性——不会出现"角色改了、权限还停在半路"的脏数据。对新手来说,这比维护"增/删差异"的实现可靠得多。

五、新手可以直接抄的 3 个设计要点

  1. 用户只挂角色,权限按角色批量管理:少一张"用户-权限"中间表,用户侧永远是一次 UPDATE;
  2. 菜单表兼任按钮权限:靠Permission字段 + 父子结构,一张表同时解决"看什么菜单"和"点什么按钮";
  3. 权限分配用"删光重插 + 事务":逻辑最简单、最不易出 bug 的方案。

项目还在 PermissionFilter.cs 预留了基于IAsyncAuthorizationFilter的控制器级权限过滤器(当前为占位实现),说明这套设计预留了向细粒度按钮鉴权演进的出口,而 CzarCmsEnums.cs 中的动作枚举也已为操作日志分好类。

小结

Czar.Cms 用 Manager + ManagerRole + Menu + RolePermission 四张表,把"登录认证 → 角色身份 → 菜单渲染 → 权限分配"整条链路压缩到了最短:用户查角色、角色查桥梁、桥梁查菜单,一步 JOIN 出全量导航。如果你想给自己的 ASP.NET Core 后台设计一套轻量权限体系,这个"角色 + 菜单 + 权限四表联动"的结构,是一套非常值得起步参考的极简范式。🚀

【免费下载链接】Czar.Cms.NET Core实战项目之CMS系列教程的源码,精简而又功能丰富的权限设计,内容管理设计让你轻松搭建一个ASP.NET Core2.2的网站系统.此项目准备用EFCore进行重构,敬请期待项目地址: https://gitcode.com/gh_mirrors/cz/Czar.Cms

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询