积木报表/大屏 按钮权限
本文介绍积木报表(报表设计器)与大屏/仪表盘(drag)的按钮级权限控制:如何按角色 / 权限编码控制按钮、右键菜单的显隐。
- 支持版本:
v2.5+。- 实现原理:后端在控制器方法上声明
@RequiresRoles(角色)/@RequiresPermissions(权限编码)注解,前端据此控制按钮、右键菜单的显隐,做到「前端隐藏 + 后端拦截」双重保护。- 数据来源:角色与权限编码统一通过你实现的
JmReportTokenServiceI扩展类提供,集成原理与 集成积木权限 一致。
一、整体原理
按钮权限是在原有「接口鉴权」基础上,把当前用户的角色与权限编码下发到前端,用于控制按钮与右键菜单的显隐,做到「前端不显示、后端也拦截」的双重保护。
判定规则:角色(roles) 与 权限编码(perms) 之间是 「或」(OR) 的关系——命中任意一个即放行。
| 维度 | 说明 |
|---|---|
| 角色(roles) | 命中按钮/接口声明的任意一个角色即放行;内置角色 admin、lowdeveloper、dbadeveloper,其中 admin 放行所有按钮 |
| 权限编码(perms) | 命中按钮/接口声明的任意一个权限编码即放行 |
| 二者关系 | 同时声明角色与权限编码时,满足其一即放行(角色命中 或 权限编码命中);同一维度内多个值之间同样是「或」 |
按钮隐藏只是「眼不见」,真正的安全由后端注解保证。请勿仅依赖前端隐藏。
效果对比(有权限 / 无权限)
以报表设计器列表页左侧菜单为例:未授予对应权限编码(且无命中角色)时,相关入口会自动隐藏。下图中「定时导出」(jmreport:exportJob:list)、「报表组合」(jmreport:reportGroup:list)在无权限时不再显示。
| 有权限 | 无权限 |
|---|---|
二、配置入口:实现 Token 扩展类
角色与权限编码均来自你实现的 JmReportTokenServiceI。如果不实现,积木会打印告警并放行(存在风险),因此生产环境必须实现。
下面是与 jeecgboot 集成时的完整参考实现(getPermissions 把「大屏 drag」与「积木报表 jmreport」两块按钮权限分开维护后合并返回,便于扩展):
@Component
public class JimuReportTokenService implements JmReportTokenServiceI {
/**
* 返回当前用户的角色编码
* 积木内置三个角色:admin、lowdeveloper、dbadeveloper(admin 放行所有按钮)
*/
@Override
public String[] getRoles(String token) {
// 从你的权限体系(如 jeecgboot 的 sys_role)中取出当前用户角色
return new String[]{"lowdeveloper"};
}
/**
* 返回当前用户的按钮权限编码
* 这里为演示,直接列出大屏(drag)与积木报表(jmreport)支持的全部权限编码;
* 实际项目中应从你的权限体系(如 jeecgboot 的 sys_permission)按当前用户动态返回其拥有的编码。
*/
@Override
public String[] getPermissions(String token) {
// ========== 第一块:大屏(仪表盘 BI)按钮权限 ==========
// 与 drag 模块各控制器上生效的 @RequiresPermissions 注解保持一致
String[] dragPermissions = new String[]{
"drag:datasource:testConnection", // 数据源连接测试
"drag:datasource:saveOrUpate", // 数据源新增/编辑
"drag:datasource:delete", // 数据源删除
"drag:datasource:deleteBatch", // 数据源批量删除
"drag:datasource:queryById", // 数据源详情查询
"drag:dataset:save", // 数据集保存
"drag:dataset:delete", // 数据集删除
"drag:analysis:sql", // SQL解析
"drag:design:getTotalData", // 仪表盘对Online表单展示数据
"drag:iconlib:config", // 图标库配置
"onl:drag:clear:recovery", // 清空回收站
"onl:drag:page:delete", // 仪表盘页面删除
"onl:drag:category:delete", // 仪表盘分类删除
"onl:drag:comp:add", // 组件新增
"onl:drag:comp:edit", // 组件编辑
"onl:drag:comp:delete", // 组件删除
"onl:drag:comp:deleteBatch", // 组件批量删除
"onl:drag:getRawTableData" // 获取原始表数据
};
// ========== 第二块:积木报表按钮权限 ==========
String[] jmreportPermissions = new String[]{
"jmreport:exportJob:plugin", // 导出任务-插件
"jmreport:exportJob:list", // 导出任务-列表
"jmreport:exportJob:save", // 导出任务-保存
"jmreport:exportJob:detail", // 导出任务-详情
"jmreport:exportJob:delete", // 导出任务-删除
"jmreport:exportJob:status", // 导出任务-状态变更
"jmreport:exportJob:run", // 导出任务-执行
"jmreport:map:add", // 地图-新增
"jmreport:map:delete", // 地图-删除
"jmreport:reportGroup:list", // 报表分组-列表
"jmreport:reportGroup:detail", // 报表分组-详情
"jmreport:reportGroup:save", // 报表分组-保存
"jmreport:reportGroup:delete", // 报表分组-删除
"jmreport:category:add", // 报表分类-新增
"jmreport:category:edit", // 报表分类-编辑
"jmreport:category:delete", // 报表分类-删除
"jmreport:category:reduction", // 报表分类-还原
"jmreport:category:completelyDelete",// 报表分类-彻底删除
"jmreport:category:batchMove", // 报表分类-批量移动
"jmreport:category:folderSort", // 报表分类-文件夹排序
"jmreport:datasource:testConnection",// 数据源-连接测试
"jmreport:datasource:saveOrUpate", // 数据源-新增/编辑
"jmreport:datasource:delete", // 数据源-删除
"jmreport:design:loadTableData", // 设计器-加载表数据
"jmreport:design:parseField", // 设计器-解析字段(SQL/API/JavaBean/填报处理器)
"jmreport:design:loadTable", // 设计器-库表/字段元数据查询
"jmreport:design:saveDb", // 设计器-数据集保存
"jmreport:design:filesDataset", // 设计器-文件数据集
"jmreport:design:editEnhance", // 设计器-增强代码(JS/CSS/Python)
"jmreport:datasource:query" // 数据源-查询(列表/详情)
};
// 合并两块权限后返回
return Stream.concat(Arrays.stream(dragPermissions), Arrays.stream(jmreportPermissions))
.toArray(String[]::new);
}
// ... getUsername / verifyToken 等其他方法
}
与 jeecgboot 集成时,
getRoles/getPermissions直接返回 jeecgboot 当前登录用户的角色编码和菜单按钮权限编码即可,无需额外维护。角色命中或权限编码命中,二者满足其一即可放行。
三、积木报表(报表设计器)按钮权限编码
报表设计器列表页(/jmreport/list)支持以下权限编码,可按需分配给角色:
| 权限编码 | 功能 |
|---|---|
jmreport:category:add | 新增分类/文件夹 |
jmreport:category:edit | 编辑分类 |
jmreport:category:delete | 删除分类(移入回收站) |
jmreport:category:reduction | 回收站还原 |
jmreport:category:completelyDelete | 彻底删除 / 清空回收站 |
jmreport:category:batchMove | 批量移动 |
jmreport:category:folderSort | 文件夹排序 |
jmreport:reportGroup:list | 报表分组-列表 |
jmreport:reportGroup:detail | 报表分组-详情 |
jmreport:reportGroup:save | 报表分组-保存 |
jmreport:reportGroup:delete | 报表分组-删除 |
jmreport:exportJob:list | 导出任务-列表 |
jmreport:exportJob:save | 导出任务-保存 |
jmreport:exportJob:detail | 导出任务-详情 |
jmreport:exportJob:delete | 导出任务-删除 |
jmreport:exportJob:run | 导出任务-执行 |
jmreport:exportJob:status | 导出任务-状态切换 |
jmreport:exportJob:plugin | 导出任务-插件 |
jmreport:map:add | 地图-新增 |
jmreport:map:delete | 地图-删除 |
jmreport:datasource:testConnection | 数据源-连接测试 v2.5.3+ |
jmreport:datasource:saveOrUpate | 数据源-新增/编辑 v2.5.3+ |
jmreport:datasource:delete | 数据源-删除 v2.5.3+ |
jmreport:design:loadTableData | 预览数据(SQL 数据集下浏览数据功能) |
jmreport:design:parseField | 数据集-解析字段(SQL / API / JavaBean / 填报处理器校验) v2.5.4+ |
jmreport:design:loadTable | 数据集-库表与字段元数据查询(加载表、按表名查询、查字段) v2.5.4+ |
jmreport:design:saveDb | 数据集-保存 v2.5.4+ |
jmreport:design:filesDataset | 数据集-文件数据集(新增/查询/删除/预览/单文件数据集) v2.5.4+ |
jmreport:design:editEnhance | 设计器-增强代码(JS / CSS / Python) v2.5.4+ |
jmreport:datasource:query | 数据源-查询(列表 / 详情 / 初始化) v2.5.4+ |
例如,给某角色只分配
jmreport:category:add、jmreport:category:edit,该角色在列表页就只能看到「新增分类」「编辑分类」按钮,删除、彻底删除、批量移动等按钮会被隐藏;同时对应的后端接口也会拦截无权限请求。
v2.5.3 升级注意(数据源接口新增鉴权):报表设计器的数据源接口(新增 / 编辑 / 删除 / 连接测试)此前没有生效的权限校验,任意已登录用户都能调用,存在通过伪造 JDBC 连接串发起任意数据库连接的安全风险(SSRF)。v2.5.3 起这些接口按上表的编码强制鉴权。
升级后如果出现「没有权限,请联系管理员分配权限!」,请给相关用户二选一补齐授权:
- 按权限编码:分配
jmreport:datasource:testConnection/saveOrUpate/delete(推荐,可细到只给测试连接、不给删除);- 按角色:分配
dbadeveloper(数据源全部操作)或lowdeveloper(仅连接测试);admin放行全部。
v2.5.4 升级注意(设计器数据集/数据源接口新增鉴权):以下设计器接口此前没有生效的权限校验,任意已登录用户都能调用 —— 可绕过设计器界面直接对平台库执行 SELECT、枚举库表结构、保存任意 SQL 数据集、实例化任意 Java 类、读取文件数据集内容、写入报表增强代码(JS/CSS/Python)。v2.5.4 起全部按上表的编码强制鉴权:
- 数据集解析字段(统一用
jmreport:design:parseField):/jmreport/queryFieldBySql、/jmreport/executeSelectApi、/jmreport/queryFieldByBean、/jmreport/form/validate/java- 库表元数据:
/jmreport/loadTable、/jmreport/queryTableName、/jmreport/queryTableFields- 数据集保存与文件数据集:
/jmreport/saveDb、/jmreport/source/datasource/files/**、/jmreport/source/dataset/files/**- 数据源查询:
/jmreport/getDataSourceByPage、/getMaintainDataSourceByPage、/getDataSourceById、/initDataSource- 增强代码与回收站:
/jmreport/editEnhance、/jmreport/clearRecycleBin升级后如果设计器相应操作提示「没有权限,请联系管理员分配权限!」,请给相关用户二选一补齐授权:
- 按权限编码:按上表分配对应编码(推荐,可细到只给查询、不给保存);
- 按角色:上述接口均同时声明了
admin/lowdeveloper/dbadeveloper(editEnhance、clearRecycleBin为admin/lowdeveloper),命中其一即放行。
四、大屏 / 仪表盘(drag)按钮权限编码
大屏与仪表盘模块(/drag/list)采用完全相同的机制:后端控制器方法上声明 @RequiresRoles / @RequiresPermissions,前端据此控制按钮与右键菜单显隐,角色与权限编码同样是「或」的关系,判定规则与上文一致。
drag 模块当前生效的权限编码(即各控制器上 @RequiresPermissions 注解声明的编码):
| 权限编码 | 功能 |
|---|---|
drag:datasource:testConnection | 数据源连接测试 |
drag:datasource:saveOrUpate | 数据源新增/编辑 |
drag:datasource:delete | 数据源删除 |
drag:datasource:deleteBatch | 数据源批量删除 |
drag:datasource:queryById | 数据源查询详情 |
drag:dataset:save | 数据集保存 |
drag:dataset:delete | 数据集删除 |
drag:analysis:sql | SQL 解析 |
drag:design:getTotalData | 对 Online 表单展示数据 |
drag:iconlib:config | 图标库配置(增/改/删) |
onl:drag:clear:recovery | 清空回收站 |
onl:drag:page:delete | 页面(大屏/仪表盘)删除 |
onl:drag:category:delete | 分类删除(移入回收站/彻底删除) |
onl:drag:comp:add | 组件新增 |
onl:drag:comp:edit | 组件编辑 |
onl:drag:comp:delete | 组件删除 |
onl:drag:comp:deleteBatch | 组件批量删除 |
onl:drag:getRawTableData | 获取表格原始数据 |
分配权限时请保持编码与控制器上
@RequiresPermissions注解完全一致(区分大小写)。
五、常见问题
Q:分配了权限,按钮还是不显示?
- 确认
getPermissions真实返回了对应编码,且与按钮/注解声明的编码完全一致(区分大小写、冒号分隔); - 或给当前用户分配命中的角色(角色与权限编码是「或」的关系,命中其一即放行;
admin放行所有); - 确认已实现
JmReportTokenServiceI,否则空角色/空权限会被当作「无权限」隐藏按钮。
Q:操作时提示「没有权限,请联系管理员分配权限!」?
- 这是后端注解拦截返回的提示,说明该接口需要对应角色或权限编码,给当前用户补充相应角色或编码即可。
Q:只想前端隐藏、后端不拦截可以吗?
- 不建议。前端隐藏只是体验层,后端注解才是安全边界,二者使用同一套编码,保持一致即可。