Commit 128a0e3bd3847d11b7f2f9e169dd36fce3b0b581
1 parent
dcdde362
fix(report): 补齐积木报表超级管理员权限
- 按当前积木2.5.4权限注解与默认实现补齐51项权限,统一为单个数组 - 保留超级管理员判断、普通用户权限及原有认证和签名校验 - 补充权限与角色的管理员、普通用户及未登录场景单测 参考 Gitee !1600:https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1600
Showing
2 changed files
with
195 additions
and
10 deletions
yudao-module-report/src/main/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImpl.java
| ... | ... | @@ -167,20 +167,65 @@ public class JmReportTokenServiceImpl implements JmReportTokenServiceI { |
| 167 | 167 | TenantContextHolder.setTenantId(loginUser.getTenantId()); |
| 168 | 168 | |
| 169 | 169 | // 参见文档 https://help.jimureport.com/prodSafe/ 文档 |
| 170 | - // 适配:如果是本系统的管理员,则返回积木报表(仪表盘/大屏设计器)的所有权限指令 | |
| 170 | + // 适配:如果是本系统的管理员,则返回积木报表(仪表盘/大屏设计器、报表设计器)的所有权限指令 | |
| 171 | 171 | // 如果不处理,会碰到 https://t.zsxq.com/yzlkA 反馈的问题 |
| 172 | + // 权限清单参考 https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1600 | |
| 172 | 173 | Long userId = SecurityFrameworkUtils.getLoginUserId(); |
| 173 | 174 | if (permissionApi.hasAnyRoles(userId, RoleCodeEnum.SUPER_ADMIN.getCode())) { |
| 174 | 175 | return new String[]{ |
| 175 | - "drag:datasource:testConnection", // 数据库连接测试 | |
| 176 | - "drag:datasource:saveOrUpate", // 数据源保存 | |
| 177 | - "drag:datasource:delete", // 数据源删除 | |
| 178 | - "drag:analysis:sql", // SQL解析 | |
| 179 | - "drag:design:getTotalData", // 展示Online表单数据 | |
| 180 | - "drag:dataset:save", // 数据集保存 | |
| 181 | - "drag:dataset:delete", // 数据集删除 | |
| 182 | - "onl:drag:clear:recovery", // 清空回收站 | |
| 183 | - "onl:drag:page:delete" // 数据删除 | |
| 176 | + // ========== 第一块:大屏(仪表盘 BI)按钮权限 ========== | |
| 177 | + "drag:datasource:testConnection", // 数据源连接测试 | |
| 178 | + "drag:datasource:saveOrUpate", // 数据源新增/编辑 | |
| 179 | + "drag:datasource:delete", // 数据源删除 | |
| 180 | + "drag:datasource:deleteBatch", // 数据源批量删除 | |
| 181 | + "drag:datasource:queryById", // 数据源详情查询 | |
| 182 | + "drag:dataset:save", // 数据集保存 | |
| 183 | + "drag:dataset:delete", // 数据集删除 | |
| 184 | + "drag:analysis:sql", // SQL解析 | |
| 185 | + "drag:design:getTotalData", // 仪表盘对Online表单展示数据 | |
| 186 | + "drag:iconlib:config", // 图标库配置 | |
| 187 | + "onl:drag:clear:recovery", // 清空回收站 | |
| 188 | + "onl:drag:page:delete", // 仪表盘页面删除 | |
| 189 | + "onl:drag:category:delete", // 仪表盘分类删除 | |
| 190 | + "onl:drag:comp:add", // 组件新增 | |
| 191 | + "onl:drag:comp:edit", // 组件编辑 | |
| 192 | + "onl:drag:comp:delete", // 组件删除 | |
| 193 | + "onl:drag:comp:deleteBatch", // 组件批量删除 | |
| 194 | + "onl:drag:getRawTableData", // 获取原始表数据 | |
| 195 | + // ========== 第二块:积木报表按钮权限 ========== | |
| 196 | + "jmreport:exportJob:plugin", // 导出任务-插件 | |
| 197 | + "jmreport:exportJob:list", // 导出任务-列表 | |
| 198 | + "jmreport:exportJob:save", // 导出任务-保存 | |
| 199 | + "jmreport:exportJob:detail", // 导出任务-详情 | |
| 200 | + "jmreport:exportJob:delete", // 导出任务-删除 | |
| 201 | + "jmreport:exportJob:status", // 导出任务-状态变更 | |
| 202 | + "jmreport:exportJob:run", // 导出任务-执行 | |
| 203 | + "jmreport:exportJob:export", // 导出任务-导出 | |
| 204 | + "jmreport:map:add", // 地图-新增 | |
| 205 | + "jmreport:map:delete", // 地图-删除 | |
| 206 | + "jmreport:reportGroup:list", // 报表分组-列表 | |
| 207 | + "jmreport:reportGroup:detail", // 报表分组-详情 | |
| 208 | + "jmreport:reportGroup:save", // 报表分组-保存 | |
| 209 | + "jmreport:reportGroup:delete", // 报表分组-删除 | |
| 210 | + "jmreport:category:add", // 报表分类-新增 | |
| 211 | + "jmreport:category:edit", // 报表分类-编辑 | |
| 212 | + "jmreport:category:delete", // 报表分类-删除 | |
| 213 | + "jmreport:category:reduction", // 报表分类-还原 | |
| 214 | + "jmreport:category:completelyDelete", // 报表分类-彻底删除 | |
| 215 | + "jmreport:category:batchMove", // 报表分类-批量移动 | |
| 216 | + "jmreport:category:folderSort", // 报表分类-文件夹排序 | |
| 217 | + "jmreport:datasource:testConnection", // 数据源-连接测试 | |
| 218 | + "jmreport:datasource:saveOrUpate", // 数据源-新增/编辑 | |
| 219 | + "jmreport:datasource:delete", // 数据源-删除 | |
| 220 | + "jmreport:datasource:query", // 数据源-查询(列表/详情) | |
| 221 | + "jmreport:design:loadTableData", // 设计器-加载表数据 | |
| 222 | + "jmreport:design:parseField", // 设计器-解析字段(SQL/API/JavaBean/填报处理器) | |
| 223 | + "jmreport:design:loadTable", // 设计器-库表/字段元数据查询 | |
| 224 | + "jmreport:design:saveDb", // 设计器-数据集保存 | |
| 225 | + "jmreport:design:filesDataset", // 设计器-文件数据集 | |
| 226 | + "jmreport:design:editEnhance", // 设计器-增强代码(JS/CSS/Python) | |
| 227 | + "jmreport:ai:tableMeta", // AI-表元数据管理 | |
| 228 | + "jimu:chat2bi:permEdit" // Chat2BI-权限编辑 | |
| 184 | 229 | }; |
| 185 | 230 | } |
| 186 | 231 | return null; | ... | ... |
yudao-module-report/src/test/java/cn/iocoder/yudao/module/report/framework/jmreport/core/service/JmReportTokenServiceImplTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.report.framework.jmreport.core.service; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.ArrayUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.biz.system.oauth2.OAuth2TokenCommonApi; | |
| 5 | +import cn.iocoder.yudao.framework.common.biz.system.permission.PermissionCommonApi; | |
| 6 | +import cn.iocoder.yudao.framework.security.config.SecurityProperties; | |
| 7 | +import cn.iocoder.yudao.framework.security.core.LoginUser; | |
| 8 | +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | |
| 9 | +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | |
| 10 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | |
| 11 | +import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; | |
| 12 | +import org.junit.jupiter.api.AfterEach; | |
| 13 | +import org.junit.jupiter.api.Test; | |
| 14 | +import org.mockito.InjectMocks; | |
| 15 | +import org.mockito.Mock; | |
| 16 | +import org.springframework.mock.web.MockHttpServletRequest; | |
| 17 | +import org.springframework.security.core.context.SecurityContextHolder; | |
| 18 | + | |
| 19 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; | |
| 20 | +import static org.junit.jupiter.api.Assertions.*; | |
| 21 | +import static org.mockito.Mockito.verifyNoInteractions; | |
| 22 | +import static org.mockito.Mockito.when; | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * {@link JmReportTokenServiceImpl} 的单元测试类 | |
| 26 | + * | |
| 27 | + * @author 芋道源码 | |
| 28 | + */ | |
| 29 | +public class JmReportTokenServiceImplTest extends BaseMockitoUnitTest { | |
| 30 | + | |
| 31 | + @InjectMocks | |
| 32 | + private JmReportTokenServiceImpl jmReportTokenService; | |
| 33 | + | |
| 34 | + @Mock | |
| 35 | + private OAuth2TokenCommonApi oauth2TokenApi; | |
| 36 | + @Mock | |
| 37 | + private PermissionCommonApi permissionApi; | |
| 38 | + @Mock | |
| 39 | + private SecurityProperties securityProperties; | |
| 40 | + | |
| 41 | + @AfterEach | |
| 42 | + public void tearDown() { | |
| 43 | + SecurityContextHolder.clearContext(); | |
| 44 | + TenantContextHolder.clear(); | |
| 45 | + } | |
| 46 | + | |
| 47 | + @Test | |
| 48 | + public void testGetPermissions_superAdmin() { | |
| 49 | + // 准备参数 | |
| 50 | + Long userId = randomLongId(); | |
| 51 | + Long tenantId = randomLongId(); | |
| 52 | + SecurityFrameworkUtils.setLoginUser(new LoginUser().setId(userId).setTenantId(tenantId), | |
| 53 | + new MockHttpServletRequest()); | |
| 54 | + // mock 方法 | |
| 55 | + when(permissionApi.hasAnyRoles(userId, RoleCodeEnum.SUPER_ADMIN.getCode())).thenReturn(true); | |
| 56 | + | |
| 57 | + // 调用 | |
| 58 | + String[] permissions = jmReportTokenService.getPermissions("token"); | |
| 59 | + // 断言:原有的大屏权限仍保留 | |
| 60 | + assertTrue(ArrayUtil.containsAll(permissions, "drag:datasource:testConnection", "drag:analysis:sql", | |
| 61 | + "onl:drag:page:delete")); | |
| 62 | + // 断言:大屏只校验权限、未配置时超级管理员会被拒绝的三处 | |
| 63 | + assertTrue(ArrayUtil.containsAll(permissions, "drag:datasource:queryById", "drag:datasource:deleteBatch", | |
| 64 | + "onl:drag:getRawTableData")); | |
| 65 | + // 断言:报表设计器的扩展权限 | |
| 66 | + assertTrue(ArrayUtil.containsAll(permissions, "jmreport:datasource:query", "jmreport:exportJob:export", | |
| 67 | + "jmreport:ai:tableMeta")); | |
| 68 | + assertEquals(permissions.length, ArrayUtil.distinct(permissions).length); | |
| 69 | + assertEquals(tenantId, TenantContextHolder.getTenantId()); | |
| 70 | + } | |
| 71 | + | |
| 72 | + @Test | |
| 73 | + public void testGetPermissions_notSuperAdmin() { | |
| 74 | + // 准备参数 | |
| 75 | + Long userId = randomLongId(); | |
| 76 | + Long tenantId = randomLongId(); | |
| 77 | + SecurityFrameworkUtils.setLoginUser(new LoginUser().setId(userId).setTenantId(tenantId), | |
| 78 | + new MockHttpServletRequest()); | |
| 79 | + // mock 方法 | |
| 80 | + when(permissionApi.hasAnyRoles(userId, RoleCodeEnum.SUPER_ADMIN.getCode())).thenReturn(false); | |
| 81 | + | |
| 82 | + // 调用 | |
| 83 | + String[] permissions = jmReportTokenService.getPermissions("token"); | |
| 84 | + // 断言 | |
| 85 | + assertNull(permissions); | |
| 86 | + assertEquals(tenantId, TenantContextHolder.getTenantId()); | |
| 87 | + } | |
| 88 | + | |
| 89 | + @Test | |
| 90 | + public void testGetPermissions_notLogin() { | |
| 91 | + // 调用 | |
| 92 | + String[] permissions = jmReportTokenService.getPermissions("token"); | |
| 93 | + // 断言 | |
| 94 | + assertNull(permissions); | |
| 95 | + assertNull(TenantContextHolder.getTenantId()); | |
| 96 | + verifyNoInteractions(permissionApi); | |
| 97 | + } | |
| 98 | + | |
| 99 | + @Test | |
| 100 | + public void testGetRoles_superAdmin() { | |
| 101 | + // 准备参数 | |
| 102 | + Long userId = randomLongId(); | |
| 103 | + Long tenantId = randomLongId(); | |
| 104 | + SecurityFrameworkUtils.setLoginUser(new LoginUser().setId(userId).setTenantId(tenantId), | |
| 105 | + new MockHttpServletRequest()); | |
| 106 | + // mock 方法 | |
| 107 | + when(permissionApi.hasAnyRoles(userId, RoleCodeEnum.SUPER_ADMIN.getCode())).thenReturn(true); | |
| 108 | + | |
| 109 | + // 调用 | |
| 110 | + String[] roles = jmReportTokenService.getRoles("token"); | |
| 111 | + // 断言 | |
| 112 | + assertArrayEquals(new String[]{"admin"}, roles); | |
| 113 | + assertEquals(tenantId, TenantContextHolder.getTenantId()); | |
| 114 | + } | |
| 115 | + | |
| 116 | + @Test | |
| 117 | + public void testGetRoles_notSuperAdmin() { | |
| 118 | + // 准备参数 | |
| 119 | + Long userId = randomLongId(); | |
| 120 | + SecurityFrameworkUtils.setLoginUser(new LoginUser().setId(userId).setTenantId(randomLongId()), | |
| 121 | + new MockHttpServletRequest()); | |
| 122 | + // mock 方法 | |
| 123 | + when(permissionApi.hasAnyRoles(userId, RoleCodeEnum.SUPER_ADMIN.getCode())).thenReturn(false); | |
| 124 | + | |
| 125 | + // 调用 | |
| 126 | + String[] roles = jmReportTokenService.getRoles("token"); | |
| 127 | + // 断言 | |
| 128 | + assertNull(roles); | |
| 129 | + } | |
| 130 | + | |
| 131 | + @Test | |
| 132 | + public void testGetRoles_notLogin() { | |
| 133 | + // 调用 | |
| 134 | + String[] roles = jmReportTokenService.getRoles("token"); | |
| 135 | + // 断言 | |
| 136 | + assertNull(roles); | |
| 137 | + verifyNoInteractions(permissionApi); | |
| 138 | + } | |
| 139 | + | |
| 140 | +} | ... | ... |