ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

后台管理系统权限控制实战:RBAC模型与按钮权限实现

后台管理系统权限控制实战:RBAC模型与按钮权限实现 做后台管理系统权限控制永远是绕不开的课题做后台管理系统做得多了权限控制永远是绕不开也最容易拖延的模块。小到内部工具后台大到企业级中台排需求时总有一句谁能看这个菜单、谁能点这个按钮、谁能调这个接口。如果你是前后端分离架构用的是 Spring Boot Vue 这套主流组合还发现按钮权限怎么控制都没头绪那这篇应该能给你一条清晰的路。标题里的Hadess我按多数同类快速开发脚手架的惯例来理解它提供一个集中式的权限管理模块把用户、角色、菜单、按钮权限的管理整合在一起后端负责认证和接口鉴权前端负责页面和按钮的匹配显隐。如果你刚接触这类项目或者正在给老系统补权限功能我会把整套链路——从数据库表设计、后端接口鉴权到前端 Vue 的按钮权限控制——从头到尾拆开讲尽量让你照着思路就能落地。这篇适合三种人看后端要接权限模块的、前端要写按钮权限控制的、以及从头搭后台管理系统的全栈。下面内容不挑框架版本核心思路在 Spring Boot 2.x/3.x 上都成立Vue 2 和 Vue 3 也都能用我会把差异点单独标出来。1. 权限控制的核心概念与整体设计思路1.1 先搞清楚权限控制到底在控制什么很多新手一上来就写代码结果写着写着就乱。我建议先想清楚一个基础问题权限控制到底控制哪几层。第一层是接口权限也就是后端接口谁能调用。这是安全底线前端做得再好接口不设防权限就是摆设。比如删除用户的接口必须只有超级管理员能调。第二层是页面权限也就是菜单和路由。普通用户登录后不该看到系统管理这个菜单也不该能直接输 URL 跳到对应页面。第三层是按钮权限也就是页面上的操作元素。同样是用户列表页管理员能看到新增用户按钮普通运营只能看列表和导出这就是按钮权限。大多数项目卡在第三层。因为接口权限后端好控制页面权限靠路由守卫也能搞定但按钮权限往往散落在每个页面的模板里一不小心就漏掉。而且按钮权限做不好经常出现权限码配了但按钮不消失刷新一下按钮又出来了这种玄学问题。所以这篇我会重点讲 Vue 侧按钮权限的几种实现和坑。1.2 RBAC 模型目前最主流、最不容易出错的方案说到权限控制绝大多数项目都会落到 RBAC基于角色的访问控制模型上。它的核心思想是用户不直接绑定权限而是绑定角色角色再绑定权限。举个例子你给张三绑定管理员角色管理员角色拥有用户管理菜单和新增用户删除用户两个按钮权限。过两天张三需要限制一下只让他新增不让删除那只需要改角色和权限的关联关系不需要动张三的用户数据。这就是中间加一层角色的好处解耦维护成本低权限调整灵活。对应到数据库就是经典的五张表表名作用sys_user用户表存登录名、密码、状态sys_role角色表存角色名称、标识如 admin、operatorsys_menu菜单权限表存菜单和按钮用类型字段区分sys_user_role用户-角色关联表sys_role_menu角色-菜单/权限关联表这套模型最直观的优点是菜单和按钮都放在同一张 sys_menu 表里通过 type 字段区分比如 0-目录、1-菜单、2-按钮角色的权限集合就是它关联的所有 menu 记录。后面要控制按钮显隐查一下当前用户有没有对应权限码就行。比 RBAC 更复杂的还有 ABAC基于属性的访问控制按用户属性、资源属性、环境条件做动态判断。那是大型政企项目或云平台的玩法对中小型后台管理系统来说RBAC 已经能覆盖九成需求而且容易理解、好交接。我个人的原则是没有明确复杂场景需求前别引入 ABAC不然团队沟通成本会直线上升。1.3 Hadess 这类脚手架的权限设计定位市面上做权限控制的方案很多Spring Security、Apache Shiro、Sa-Token以及各种全家桶脚手架。为什么选择 Hadess 这类集成了权限模块的脚手架我的判断标准就三条第一是不是开箱即用。Spring Security 功能强但配置门槛高光是记住一堆过滤器链、AuthenticationManager 的用法就要折腾一阵子。Hadess 这类把用户认证、token 签发、权限校验的代码都封装好了你只需要关注业务接口开发效率高很多。第二是不是前后端分离友好。传统 Session 方案在前后端分离下要处理跨域、Cookie 携带等问题麻烦。基于 JWT 的无状态认证天然适合前后端分离Hadess 这类脚手架通常默认就是 JWT 方案前端拿到 token 存起来每次请求头带上即可。第三权限模型是不是够直观。我见过不少项目把权限表设计得极其复杂结果是写 SQL 的人自己都晕。Hadess 这类框架普遍采用上面说的 RBAC 五表结构权限码直接挂在菜单表上前后端都能很自然地对应起来。当然选型和取舍要结合团队情况。如果项目需要极细粒度的数据权限比如业务员只能看自己负责的订单RBAC 是不够的你需要在权限框架之外单独做数据权限过滤这个后面我可以专门写一篇。如果是要快速交付一个内部管理系统那 Hadess 这类方案的性价比非常高。2. 核心细节解析与后端权限控制实操2.1 数据库模型设计权限数据到底怎么存刚才列了五张表现在把关键字段展开说说。这是后端权限控制的地基设计得好不好直接影响后续所有代码。sys_user表核心字段字段类型说明idbigint主键usernamevarchar(50)登录名通常唯一passwordvarchar(100)加密后的密码绝不能存明文statustinyint账号状态1-启用0-禁用create_timedatetime创建时间密码加密我建议用 BCrypt。它自带加盐机制同一个密码每次加密结果都不一样而且验证算法内置比简单的 MD5 加盐靠谱得多。千万别用明文密码也别自己发明加密算法现实中踩过坑的人太多了。sys_role表核心字段字段类型说明idbigint主键role_namevarchar(50)角色名如管理员role_keyvarchar(50)角色标识如admin代码里判断用statustinyint状态这里要说一个细节role_key是给程序识别用的比如接口注解里判断hasRole(admin)role_name是给人看的。两者分开能避免后续改名影响逻辑。sys_menu表核心字段字段类型说明idbigint主键parent_idbigint父菜单 ID顶级为 0menu_namevarchar(50)菜单名称menu_typetinyint0-目录1-菜单2-按钮permsvarchar(100)权限标识如system:user:addpathvarchar(200)前端路由地址菜单才有iconvarchar(50)图标sort_orderint排序perms字段是整个按钮权限的灵魂。它类似一个命名空间常见格式是模块:实体:操作比如system:user:add、system:user:delete、system:role:edit。前后端都用这个字符串做匹配所以一定要规范命名不然维护起来会疯。关联表就简单了sys_user_roleuser_idrole_idsys_role_menurole_idmenu_id有些人会问能不能用用户直接关联权限不要角色表可以但你会发现每个用户都要单独配权限人一多就崩溃。RBAC 的价值就在角色这一层它能让你批量分配权限。2.2 认证流程登录态是怎么建立的后端权限控制的入口是认证。Hadess 这类框架的标准流程是前端提交用户名、密码到/login接口。后端校验用户名密码是否正确、账号是否被禁用。校验通过后生成一个 JWT token返回给前端。前端把 token 存起来localStorage 或 Pinia/Vuex后续每个请求在 header 里带上Authorization: Bearer token。后端拦截器解析 token拿到当前用户信息再判断有没有权限。JWT 的核心优点是无状态。服务端不用存 sessiontoken 里就包含用户 ID、过期时间等信息适合多实例部署。但要注意一点JWT 一旦签发在过期之前是没法主动失效的除非引入黑名单机制所以 token 过期时间不能设置太长一般建议 8 到 24 小时后台管理系统可以更短。我习惯的 JWT 负载结构是这样{ userId: 1024, username: zhangsan, roleKey: admin, exp: 1700000000 }不建议把权限列表也塞进 JWT。为什么权限是经常变动的塞进 token 会导致用户改了角色后要等 token 过期才能生效。正确做法是token 只做身份识别权限列表每次请求时动态查或者登录后缓存一份在 Redis配合缓存失效机制使用。2.3 后端接口鉴权每个接口怎么保护起来认证解决你是谁授权解决你能干什么。在 Hadess 这类框架里接口鉴权通常通过两种方式配合方式一是全局拦截器。拦截器负责解析 token、把用户信息放入上下文。比如自定义一个AuthInterceptor把userId、roleKey这些信息放到ThreadLocal或请求属性里方便后续业务代码取用。方式二是权限注解。在需要鉴权的接口方法上加注解比如RequiresPermission(system:user:add) PostMapping(/user) public Result addUser(RequestBody UserDTO user) { return Result.success(userService.add(user)); }注解的校验逻辑可以写在 AOP 切面里从上下文取用户权限集合看是否包含system:user:add有就放行没有就抛异常并返回无权限。这里有一个常见的坑权限注解判断的是当前用户拥有哪些权限所以登录时除了返回 token最好同时返回当前用户的权限码列表前端和后端校验都用这一份数据。Hadess 这类框架的登录接口通常直接返回两部分{ token: eyJhbGciOi..., userInfo: { userId: 1024, username: zhangsan, roles: [admin], permissions: [system:user:list, system:user:add] } }前端拿到 permissions 后存起来用来控制按钮显隐后端接口校验时从数据库或缓存里再查一次。两边用的是同一套权限码就能保持一致。3. 实操过程Hadess 快速接入步骤3.1 环境准备与基础配置我按下述环境举例实际以你项目版本为准JDK 1.8 或 11Maven 3.6MySQL 5.7 / 8.0Redis 5.0用于缓存用户信息和权限非必须但建议有Node.js 14前端引入 Hadess 依赖pom.xml 中参考dependency groupIdcom.hadess/groupId artifactIdhadess-framework/artifactId version2.1.0/version /dependency核心配置项通常是数据源、Redis、JWT 密钥和过期时间spring: datasource: url: jdbc:mysql://localhost:3306/hadess_demo?useUnicodetruecharacterEncodingutf8useSSLfalse username: root password: 123456 redis: host: localhost port: 6379 database: 0 hadess: jwt: # 线下环境随意生成线上一定要换成随机长字符串 secret: hadess-demo-secret-key-change-me expire-hours: 24配置里有两个细节值得注意一是 JWT 密钥。很多人图省事直接填一个固定字符串线上会被泄露导致 token 可被伪造。推荐用命令行生成一个足够长的随机串比如openssl rand -base64 64的产物。二是 token 过期时间。太短影响体验太长不安全。我做后台系统一般设置 12 到 24 小时再通过前端刷新 token 或重新登录来续期。3.2 初始化权限表与基础数据数据库表结构可以直接用 Hadess 提供的初始化脚本也可以按前面五表结构自己建。表建好后至少要初始化这些数据一个超级管理员角色admin绑定所有菜单权限。一个测试普通角色operator只绑部分菜单和按钮。一个管理员账号、一个普通测试账号。我用 SQL 示例说明-- 初始化角色 INSERT INTO sys_role (id, role_name, role_key, status) VALUES (1, 超级管理员, admin, 1); INSERT INTO sys_role (id, role_name, role_key, status) VALUES (2, 运营人员, operator, 1); -- 初始化用户 -- 密码为 BCrypt 加密后的结果生产环境通过代码生成 INSERT INTO sys_user (id, username, password, status) VALUES (1, admin, $2a$10$xxxxxxxxxxxxxxxxxxxxxx, 1); INSERT INTO sys_user (id, username, password, status) VALUES (2, operator, $2a$10$yyyyyyyyyyyyyyyyyyyyy, 1); -- 建立用户角色关系 INSERT INTO sys_user_role (user_id, role_id) VALUES (1, 1); INSERT INTO sys_user_role (user_id, role_id) VALUES (2, 2); -- 初始化菜单/权限目录、菜单、按钮 INSERT INTO sys_menu (id, parent_id, menu_name, menu_type, perms, path) VALUES (1, 0, 用户管理, 1, NULL, /user); INSERT INTO sys_menu (id, parent_id, menu_name, menu_type, perms, path) VALUES (2, 1, 用户列表, 2, system:user:list, NULL); INSERT INTO sys_menu (id, parent_id, menu_name, menu_type, perms, path) VALUES (3, 1, 新增用户, 2, system:user:add, NULL); INSERT INTO sys_menu (id, parent_id, menu_name, menu_type, perms, path) VALUES (4, 1, 删除用户, 2, system:user:delete, NULL);这里有个我需要特别提醒的点按钮权限不要做成只挂在某个菜单下而是通过sys_role_menu关联。也就是说一个角色能看到的按钮完全由角色与菜单的关联关系决定。这部分数据一般通过 Hadess 自带的管理页面来配置不用手动写 SQL。3.3 实现登录接口登录接口的核心逻辑拆开看其实不复杂PostMapping(/login) public ResultLoginResponse login(RequestBody LoginRequest req) { // 1. 根据用户名查用户 User user userService.getByUsername(req.getUsername()); if (user null || !BCrypt.checkpw(req.getPassword(), user.getPassword())) { return Result.error(用户名或密码错误); } if (user.getStatus() ! 1) { return Result.error(账号已被禁用); } // 2. 查询角色和权限集合 ListString roles roleService.getRoleKeysByUserId(user.getId()); SetString permissions permissionService.getPermsByUserId(user.getId()); // 3. 生成 JWT String token jwtUtil.createToken(user.getId(), user.getUsername(), roles); // 4. 返回结果 LoginResponse resp new LoginResponse(); resp.setToken(token); resp.setUserInfo(new UserInfo(user.getId(), user.getUsername(), roles, permissions)); return Result.success(resp); }有两点经验分享一是登录接口返回的 permissions 一定要去重因为一个用户可能关联多个角色而多个角色可能绑定了同一个按钮权限。用Set接收就能天然去重。二是登录接口本身要加频率限制防止暴力破解。最简单的做法是配合 Redis 做滑动窗口限流比如 5 分钟内错误次数超过 10 次就锁定半小时。这个防护在暴露到公网的系统中尤其重要。3.4 写一个受保护的接口并验证权限登录打通后写一个受保护的用户列表接口验证效果。定义权限注解Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface RequiresPermission { String value(); }写切面做权限校验Aspect Component public class PermissionAspect { Around(annotation(requiresPermission)) public Object checkPermission(ProceedingJoinPoint joinPoint, RequiresPermission requiresPermission) throws Throwable { // 从当前请求上下文中拿用户权限集合 SetString permissions SecurityContext.getCurrentUserPermissions(); if (!permissions.contains(requiresPermission.value())) { throw new ForbiddenException(无权限访问); } return joinPoint.proceed(); } }接口上直接标注GetMapping(/user/page) RequiresPermission(system:user:list) public ResultPageResultUserVO pageUser(int page, int size) { return Result.success(userService.pageUser(page, size)); } PostMapping(/user) RequiresPermission(system:user:add) public ResultVoid addUser(RequestBody UserDTO dto) { userService.addUser(dto); return Result.success(); } DeleteMapping(/user/{id}) RequiresPermission(system:user:delete) public ResultVoid deleteUser(PathVariable Long id) { userService.deleteUser(id); return Result.success(); }测试时用 admin 登录调用删除接口返回成功再用 operator 登录调用同一个接口应该返回 403 或无权限。这就是后端接口鉴权的完整闭环。4. 前端 Vue 按钮权限控制实战后端梳理清楚后前端就有依据了。Vue 里控制按钮权限本质就是一句话判断当前用户的 permission 集合里有没有对应的权限码有就渲染没有就不渲染。但具体实现有好几种做法各有坑我一个个说。4.1 前端权限控制的整体流程先看整体链路不然容易迷失用户登录拿到 token 和 permissions 列表。把 token 存到 localStorage把 permissions 存到 Pinia/Vuex。前端路由配置里给需要权限的页面加 meta.permission。路由守卫里判断用户是否已登录、是否刷新导致状态丢失。进入页面后模板中通过自定义指令或方法判断每个按钮的权限。按钮级控制不依赖后端返回的 HTML而是纯前端渲染判断。这里有个很重要的原则前端控制按钮只是提升体验不是安全边界。真正安全的还是后端接口鉴权。就算前端按钮没渲染恶意用户直接调接口后端也能拦截。所以做按钮权限的前提是后端接口必须已经做了鉴权两者是配合关系不是替代关系。4.2 三种常见实现方式对比Vue 里做按钮权限常见就三种方式一v-if 权限判断方法el-button v-ifhasPerm(system:user:add) clickhandleAdd新增用户/el-buttonhasPerm是一个全局方法内部去 store 里的 permissions 数组查一下function hasPerm(perm) { return permissions.includes(perm) }这种方式最直观适合按钮不多的小项目。缺点是每个按钮都要写一遍判断代码重复度高而且如果权限集合是异步加载的要小心初始为空数组时按钮会全部消失。方式二自定义指令 v-permissionel-button v-permissionsystem:user:add clickhandleAdd新增用户/el-button指令代码统一封装用起来更简洁团队协作时模板里也更干净。我推荐这个方案后面单独写实现。方式三通过全局混入 mixin 提供方法类似方式一但把 hasPerm 定义在混入里。这种方法能让每个组件直接用this.hasPerm但对 template 里的按钮还是得配合 v-if 使用体验和方式一差不多。三种方式本质相同区别在于封装层次和代码量。下面重点讲自定义指令因为它是目前团队项目里用得最多、也最优雅的做法。4.3 实现一个 v-permission 自定义指令以 Vue 3 为例在src/directives/permission.js里写import { useStore } from /store export function checkPermission(perm) { const store useStore() // store 里的 permissions 是登录后存下来的权限码数组 return store.permissions.includes(perm) } export const permissionDirective { mounted(el, binding) { const perm binding.value if (!perm) { console.warn([v-permission] 权限码不能为空) return } if (!checkPermission(perm)) { // 关键移除按钮 DOM 元素 el.parentNode el.parentNode.removeChild(el) } } }在主入口注册import { permissionDirective } from /directives/permission app.directive(permission, permissionDirective)模板这么用el-button v-permissionsystem:user:add新增用户/el-button el-button v-permissionsystem:user:delete删除用户/el-button el-button v-permissionsystem:user:export导出用户/el-button有人会问为什么不用v-if而是用移除 DOM用v-if也可以但自定义指令的好处是逻辑收敛只要一行指令就能搞定后续切权限方式比如权限码来自不同数据源只需要改指令内部实现不用全局搜索模板改代码。这个方案有一个非常典型的坑如果用户进入页面时 permissions 还没加载完指令会误判为无权限把按钮直接删掉。等权限加载完按钮也不会自动回来因为指令只在元素挂载时执行一次。解决办法有三种思路我按推荐程度排列等权限加载完再挂载页面。在路由守卫里先比对完权限确认 permissions 已存在再放行进入组件。这是最干净的方案。用 v-if 配合权限状态控制整个页面渲染时机。页面骨架可以显示但按钮区域等到权限就绪后再渲染。让指令监听 store 变化重新渲染。这个比较复杂其实没有方案 1 直觉。4.4 动态菜单与路由守卫的配合按钮权限之上还有页面权限。动态菜单的常见做法是前端拿到用户权限列表前端路由表只保留固定路由登录页、404 页动态路由用户管理、角色管理等由后端权限菜单数据动态生成并注册。路由守卫里做这件事router.beforeEach(async (to, from, next) { const store useStore() if (!store.token) { next(/login?redirect${to.fullPath}) return } // 第一次进入时拉取权限并生成动态路由 if (!store.permissionReady) { await store.fetchUserInfo() // 拉取用户信息、角色、权限 const accessRoutes generateRoutes(store.menuList) accessRoutes.forEach(route router.addRoute(route)) store.setPermissionReady(true) next({ ...to, replace: true }) return } next() })这里最常见的问题是刷新页面后 store 里的 token 和 permissions 都丢了。localStorage 里只有 token但用户信息和权限没有持久化又或者持久化了但取值顺序不对。我的建议是token 存在 localStorage 或 cookie刷新不丢。permissions 在刷新后用 token 重新请求后端接口获取不要在 localStorage 存一份过期的权限副本。页面刷新时根组件会重新挂载路由守卫再次执行此时要重新拉取权限再放行。不要过度依赖 localStorage 去持久化权限因为后端角色权限一变前端旧缓存就是脏数据会引发权限改了但页面按钮还显示着的问题。5. 常见问题与排查技巧实录这节我把实操中真正频繁出现的问题列成速查表形式涉及前后端的都有。5.1 权限码拿到了但按钮还是不消失大概率是权限码字符串不一致。常见原因后端权限码是system:user:add前端指令里写的是system/user/add或者数据库的 perms 字段有空格、大小写差异。排查时先 console.log 打印当前用户的 permissions再对比模板里的字符串一眼就能看出来。另一个原因是指令移除时机出了问题。如果按钮是用v-for循环渲染的指令作用在循环内层元素上时要等循环数据到了再判断。此时建议权限码本身在数组里但按钮还是被删了优先怀疑是自定义指令执行时 permissions 还没存好。5.2 刷新页面后按钮权限丢失这是最经典的问题。刷新导致 store 重置permissions 变成空数组所有按钮一瞬间消失过一会儿又出现或者一直消失。我的排查顺序是看是否在路由守卫里重新拉取了用户信息。如果没有刷新后 store 本来就是空按钮当然不显示。看在拉取 userInfo 的接口之前页面是不是就已经被放行了。如果放行时机早于权限加载完按钮会被误删。看动态路由是否重复添加。刷新后addRoute重复注册会警告甚至导致路由异常。经验做法是把放行节点放在权限加载完成之后宁可先显示一个全局 loading也别让页面带着空权限渲染一次。这个一次空渲染造成的坑几乎每个人都踩过。5.3 后端接口返回 403但前端按钮明明显示了这说明前后端的权限数据不同步。按钮显示说明前端有权限码接口拒绝说明后端校验时没查到。可能原因Redis 缓存里存了旧权限数据。登录后后端会查权限并缓存但缓存没有在角色权限变更时同步失效。解决方法是修改角色权限后清除相关用户的缓存。前后端权限码大小写或命名规则不一致后端用system:user:Delete前端写的system:user:delete。用户同时有多个角色后端返回给前端的 permissions 是全部角色并集但后端拦截器只校验了当前角色集合中的一部分导致逻辑不一致。排查后端时可以在切面里打印当前用户的 userId、角色集合、权限集合对照前端调用接口时传的 token 解析出的用户信息。两边对齐问题基本能定位。5.4 权限数据量大了之后查询变慢五张表关联查询数据量不大没问题但菜单权限动辄几千条时就要注意性能了。我的建议是sys_role_menu表给role_id建索引。用户权限查询可以一次性 join 出所有权限码不要逐条查。把登录用户的权限列表缓存到 Rediskey 设计成permissions:{userId}权限变更时删除缓存而不是每次都查数据库。注意缓存穿透问题用户被删除后缓存还在要连同事务一起处理。这类性能问题平时不起眼用户量大了就会暴露趁早把缓存方案做好后面会轻松很多。5.5 按钮权限到底放前端还是后端这是很多团队争论的问题。我的建议很明确前后端都要做但定位不同。前端做按钮权限是为了用户体验——没权限的按钮不显示避免用户点了之后收到报错也减少误导。后端做接口鉴权是为了安全——不管前端怎么显示任何请求到后端都要被校验。绝对不要做的是只做前端控制、后端不校验。那样只要有人会打开控制台或者直接拿 Postman 调接口就能绕过前端逻辑执行危险操作。反过来只做后端校验、前端全显示用户体验也差。两者配合才是正解。当然对于纯展示型按钮比如查看详情如果详情接口本身已经有数据权限过滤按钮是否显示影响不大可以不做精细化控制。但我建议从项目一开始就统一规范别等到按钮多了再补那时候返工成本会很高。实际操作中我的一些体会写到这里权限控制这条链路基本就完整了。最后分享几个我实际项目中沉淀下来的习惯。第一个习惯是权限码命名规范要提前定死。我见过太多项目权限码满天飞有的叫user_add有的叫user:add有的干脆写中文备注。这个乱象会导致前端对权限码的效率极其低下。我推荐统一用模块:实体:操作的三段式比如system:user:add模块名和实体名都用单数操作名统一用 add、edit、delete、list、export 五个词这样一看就知道是干什么的。第二个习惯是权限变更实时性。权限改完用户那边半天不生效这个问题在 JWT 缓存方案下尤其常见。我给团队定过一个规则任何角色权限变更必须同步清除该角色下所有用户的权限缓存。后端写一个clearPermissionCacheByRoleId工具方法在权限管理接口里统一调用前端才不用反复登录取刷新权限。第三个习惯是预留数据权限扩展点。按钮权限解决的是能不能操作但很多业务真正难的是能操作哪些数据。比如同一个查看订单按钮A 销售只能看自己的订单B 销售经理能看整个团队的订单。如果你在做权限模块建议给用户、角色表预留一个 dept_id 或数据范围字段后面接数据权限过滤时会省很多事。我当时就是没预留后来为了做销售数据隔离改了整整一轮表结构和查询 SQL非常被动。权限控制这事说难不难说简单也不简单。难在它贯穿整个系统容易在模型清晰后一切水到渠成。照着 RBAC 模型搭好表和接口后端用注解保护接口前端用指令控制按钮这套东西足够支撑大多数后台管理系统。希望这篇能把你在权限控制上的思路理顺少走一些我当年走过的弯路。
返回列表