动态角色权限和动态权限到底API是怎么做的你懂了吗

动态角色权限和动态权限到底API是怎么做的你懂了吗

1、背景

这部分我也将其归类为RBAC权限之中的一部分

在做RBAC权限管理系统的时候,都会遇到这么一个需求

每个用户的权限是不一样的,他可以访问的页面,可以操作的菜单,包括可能操作的按钮都是不一样的

这个时候就需要由后端控制用户返回的页面以及菜单按钮权限,前端去实现动态路由,动态渲染侧边菜单栏

2、实现

接下来我们就看一下如何实现不同角色不同菜单的功能

👉现有返回

我们先要改造的就是/getInfo这个接口,现在我们返回内容如下

javascript 复制代码
{
    "code": 200,
    "data": {
        "userId": 71,
        "username": "admin",
        "password": "xxxxxx",
        "name": "admin",
        "age": null,
        "sex": null,
        "createTime": "1970-01-01 00:00:00",
        "address": null,
        "state": 1,
        "phone": null,
        "avatar": null,
        "updateTime": "1970-01-01 00:00:00",
        "userHeight": null,
        "userWeight": null,
        "disease": null,
        "isDeleted": null
    },
    "message": "欢迎你的访问!"
}

👉我们想要的返回信息

JSON 响应的表示操作成功的内容,具体信息如下:

  • **msg**: "操作成功" --- 这表示操作已成功完成。
  • **code**: 200 --- 这是成功的 HTTP 状态码,表示请求已成功处理。
  • **permissions**: ["*: *:*"] --- 这表示该用户拥有的权限,这里的 *: *:* 通常表示具有全局权限。
  • **roles**: ["admin"] --- 该用户的角色为 admin,意味着该用户是管理员。
  • **data**: 包含一些用户相关的信息:
    • **roleIds**: null --- 角色 ID 为 null,可能表示该字段目前没有关联的角色。
    • **postIds**: null --- 岗位 ID 为 null,没有关联的岗位。
    • **roleId**: null --- 单一角色 ID 为 null,可能表示没有指定具体的角色 ID。
    • **admin**: true --- 表示该用户是管理员(true 表示是,false 表示不是)。
javascript 复制代码
{
    "msg": "操作成功",
    "code": 200,
    "permissions": [
        "*:*:*"
    ],
    "roles": [
        "admin"
    ],
    "data": {
        "createBy": "admin",
        "createTime": "2025-05-26 10:07:46",
        "roleIds": null,
        "postIds": null,
        "roleId": null,
        "admin": true
    }
}

👉现有接口

现在我们模块如下,首先添加的就是角色模块

javascript 复制代码
const express = require('express');
const router = express.Router();

const connectionPool = require('../db'); // 引入数据库连接池模块
const {addCondition,addDateRangeCondition,addPagination,convertKeysToSnakeCase,convertToCamelCase} = require('../methods.js'); // 引入封装方法

//获取用户信息时,要使用 req.auth.username 获取用户名
router.get('/', (req, res) => {
  // console.log(req,'req');
  // console.log(res,'res');
  if (!req.auth || !req.auth.username) {
      return res.status(401).send({
          code: 401,
          message: '未认证用户或缺少用户名!',
      });
  }
  const values = [req.auth.username];
  let query = 'SELECT * FROM sys_user WHERE username = ?';

  connectionPool.query(query, [req.auth.username], (err, results) => {
      if (err) {
          return res.status(500).send({
              code: 500,
              message: '数据库查询错误!',
          });
      }
      if (results.length === 0) {
          return res.status(404).send({
              code: 404,
              message: '用户不存在!',
          });
      }
      res.send({
          code: 200,
          data: results[0]?convertToCamelCase(results[0]):[], // 返回用户信息
          message: '欢迎你的访问!',
      });
  });
})

module.exports = router;

👉新增的返回如下

javascript 复制代码
roles: ["admin"]

👉建立用户-角色对应表sys_user_role

需要返回不同用户对应的角色,我们就需要建立一个用户-角色对应表

javascript 复制代码
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`  (
  `user_id` bigint(0) NOT NULL COMMENT '用户ID',
  `role_id` bigint(0) NOT NULL COMMENT '角色ID',
  PRIMARY KEY (`user_id`, `role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_bin COMMENT = '用户和角色关联表' ROW_FORMAT = Dynamic;

接下来我们根据已经有的用户ID去拿对应角色表中的角色,Mysql语句根据user_id查询到sys_user_role对应的role_id,在根据role_id查询到sys_role对应role_id role_key

这里我们可以先写一个mysql测试一下

javascript 复制代码
SELECT r.role_key
    FROM sys_user_role ur
    JOIN sys_role r ON ur.role_id = r.role_id
    WHERE ur.user_id = 1 



// 直接返回信息
role_key
common

证明我们sql语句没问题,接下来完善我们的接口返回信息

👉接口返回信息

javascript 复制代码
let userroles= []; //普通角色
      let permissions= ["*:*:*"];

   // 查询用户角色
  // SQL 查询,获取用户角色的 role_key
  let queryrole = `
    SELECT r.role_key
    FROM sys_user_role ur
    JOIN sys_role r ON ur.role_id = r.role_id
    WHERE ur.user_id = ?
  `;
  let queryroleuserid=results[0].user_id;
  connectionPool.query(queryrole, [queryroleuserid], (err, roleresult) => {
    // console.log(roleresult,'roleresult');
    if(roleresult.length === 0){
      res.send({
        code: 404,
        message: '用户角色不完整,请尽快完善!',
      });
    }else{
      userroles=[];
      userroles.push(roleresult[0].role_key);
    }
    res.send({
      code: 200,
      data: results[0]?convertToCamelCase(results[0]):[], // 返回用户信息
      msg: '欢迎你的访问!',
      roles:userroles,
      permissions,
      isDefaultModifyPwd: false,
      isPasswordExpired: false,
    });
  })

👉默认角色

接下来我们测试一下新用户,这个时候新用户为

javascript 复制代码
{
    "code": 404,
    "message": "用户角色不完整,请尽快完善!"
}

这就需要我们默认一个用户角色

javascript 复制代码
let userroles= ["common"]; //普通角色


//返回信息如下--ok
roles: ["common"]

3、完善

接下来我们要完善角色对应的菜单以及按钮权限,这就需要我们建立一个对应的菜单对应表sys_role_menu

👉建立角色-菜单对应表sys_role_menu

需要返回不同角色对应的菜单,我们就需要建立一个角色-菜单对应表

javascript 复制代码
DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu`  (
  `role_id` bigint(0) NOT NULL COMMENT '角色ID',
  `menu_id` bigint(0) NOT NULL COMMENT '菜单ID',
  PRIMARY KEY (`role_id`, `menu_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = 
utf8mb3_bin COMMENT = '角色和菜单关联表' ROW_FORMAT = Dynamic;

👉逻辑编写

思考一下逻辑:

也就是我们需要使用role_id去查出对应的

接下来我们根据已经有的用户ID去拿对应角色表中的角色,Mysql语句根据user_id查询到sys_user_role对应的role_id,在根据role_id查询到sys_role_menu对应role_id的所有 menu_id,再根据所有的menu_id去拿到sys_menu中对应的所有menu_idperms权限标识

👉根据用户ID查询角色ID

javascript 复制代码
 // 根据用户ID查询角色ID
const roleQuery = `
  SELECT role_id
  FROM sys_user_role
  WHERE user_id = ?
`;
connectionPool.query(roleQuery, [queryroleuserid], (err, roleResults) => {
  console.log(roleResults[0].role_id,'roleResults');
})


//测试结果
1 roleResults

测试一下,ok

👉接下来我们就根据角色ID查询菜单ID

javascript 复制代码
// 根据用户ID查询角色ID
const roleQuery = `
SELECT role_id
FROM sys_user_role
WHERE user_id = ?
`;

connectionPool.query(roleQuery, [queryroleuserid], (err, roleResults) => {
    // console.log(roleResults[0].role_id,'roleResults');

    let role_id = roleResults[0].role_id;
    console.log(role_id,'role_id')
    // 根据角色ID查询菜单ID
    const menuQuery = `
    SELECT menu_id
    FROM sys_role_menu
    WHERE role_id IN (?)
  `;

    connectionPool.query(menuQuery, [role_id], (err, menuResults) => {
        console.log(menuResults, 'menuResults');

        if (err) {
            return res.status(500).send({
                code: 500,
                message: '查询菜单失败!',
            });
        }
    })

})




//测试结果
[{ menu_id: 1 },
 { menu_id: 2 },
 { menu_id: 3 },
 { menu_id: 4 },
 { menu_id: 100 },
 { menu_id: 104 },
]

👉根据菜单ID查询权限

javascript 复制代码
 // 第三步:根据菜单ID查询权限标识
  const permsQuery = `
    SELECT perms
    FROM sys_menu
    WHERE menu_id IN (?)
  `;
  connectionPool.query(permsQuery, [menuIds], (err, permsResults) => {
    console.log(permsResults, 'permsResults');

    const permissions = permsResults.map(result => result.perms).filter(perm => perm !== '');
    console.log(permissions, 'permissions');
  })

测试一下我们的数据

javascript 复制代码
这个时候我们得到的权限数据已经符合我们的预期了 

[
  'system:user:list',
  'system:role:list',
  'system:menu:list',
  'system:dept:list',
  'system:post:list',
  'system:dict:list',
  'system:config:list',
  'system:notice:list',
  'monitor:online:list',
  'monitor:job:list',
]

然后完善一下添加上自己对应的返回信息即可,相信这里大家都会自己操作了,然后就是自己优化一下,比较简单,我就不写了

javascript 复制代码
{
    "code": 200,
    "data": {
        "userId": 72,
        "username": "222222",
        "password": "XXXXX",
        "name": "222222",
        "age": null,
        "sex": null,
        "createTime": "1970-01-01 00:00:00",
        "address": null,
        "state": 1,
        "phone": null,
        "avatar": null,
        "updateTime": "1970-01-01 00:00:00",
        "userHeight": null,
        "userWeight": null,
        "disease": null,
        "isDeleted": null
    },
    "msg": "欢迎你的访问!",
    "msgtype": "success",
    "roles": [
        "common"
    ],
    "permissions": [
        "system:user:list",
        "system:role:list",
        "system:menu:list",
        "system:dept:list",
        "system:post:list",
        "system:dict:list",
    ],
    "isDefaultModifyPwd": false,
    "isPasswordExpired": false
}
相关推荐
00后程序员几秒前
移动端网页调试实战,iOS WebKit Debug Proxy 的应用与替代方案
后端
whitepure5 分钟前
我如何理解与追求整洁代码
java·后端·代码规范
去伪存真6 分钟前
因为rolldown-vite比vite打包速度快, 所以必须把rolldown-vite在项目中用起来🤺
前端
KubeSphere7 分钟前
Kubernetes v1.34 重磅发布:调度更快,安全更强,AI 资源管理全面进化
前端
用户83562907805115 分钟前
Java高效读取Excel表格数据教程
java·后端
yinke小琪19 分钟前
今天解析一下从代码到架构:Java后端开发的"破局"与"新生"
java·后端·架构
码出极致22 分钟前
支付平台资金强一致实践:基于 Seata TCC+DB 模式的余额扣减与渠道支付落地案例
后端·面试
wifi歪f22 分钟前
🎉 Stenciljs,一个Web Components框架新体验
前端·javascript
1024小神26 分钟前
如何快速copy复制一个网站,或是将网站本地静态化访问
前端
掘金一周26 分钟前
DeepSeek删豆包冲上热搜,大模型世子之争演都不演了 | 掘金一周 8.28
前端·人工智能·后端