Commit 97e842a59f0d7832af3a7e416d465c0c1af63433

Authored by YunaiV
1 parent f4818d26

完善 role、user、menu 删除时,对权限的影响

src/main/java/cn/iocoder/dashboard/framework/logger/apilog/core/filter/ApiAccessLogFilter.java
@@ -81,7 +81,7 @@ public class ApiAccessLogFilter extends OncePerRequestFilter { @@ -81,7 +81,7 @@ public class ApiAccessLogFilter extends OncePerRequestFilter {
81 Map<String, String> queryString, String requestBody, Exception ex) { 81 Map<String, String> queryString, String requestBody, Exception ex) {
82 // 处理用户信息 82 // 处理用户信息
83 accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request)); 83 accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request));
84 - accessLog.setUserType(WebFrameworkUtils.getUesrType(request)); 84 + accessLog.setUserType(WebFrameworkUtils.getUserType(request));
85 // 设置访问结果 85 // 设置访问结果
86 CommonResult<?> result = WebFrameworkUtils.getCommonResult(request); 86 CommonResult<?> result = WebFrameworkUtils.getCommonResult(request);
87 if (result != null) { 87 if (result != null) {
src/main/java/cn/iocoder/dashboard/framework/web/core/handler/GlobalExceptionHandler.java
@@ -269,7 +269,7 @@ public class GlobalExceptionHandler { @@ -269,7 +269,7 @@ public class GlobalExceptionHandler {
269 private void initExceptionLog(ApiErrorLogCreateDTO errorLog, HttpServletRequest request, Throwable e) { 269 private void initExceptionLog(ApiErrorLogCreateDTO errorLog, HttpServletRequest request, Throwable e) {
270 // 处理用户信息 270 // 处理用户信息
271 errorLog.setUserId(WebFrameworkUtils.getLoginUserId(request)); 271 errorLog.setUserId(WebFrameworkUtils.getLoginUserId(request));
272 - errorLog.setUserType(WebFrameworkUtils.getUesrType(request)); 272 + errorLog.setUserType(WebFrameworkUtils.getUserType(request));
273 // 设置异常字段 273 // 设置异常字段
274 errorLog.setExceptionName(e.getClass().getName()); 274 errorLog.setExceptionName(e.getClass().getName());
275 errorLog.setExceptionMessage(ExceptionUtil.getMessage(e)); 275 errorLog.setExceptionMessage(ExceptionUtil.getMessage(e));
src/main/java/cn/iocoder/dashboard/framework/web/core/util/WebFrameworkUtils.java
@@ -31,7 +31,7 @@ public class WebFrameworkUtils { @@ -31,7 +31,7 @@ public class WebFrameworkUtils {
31 return (Long) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID); 31 return (Long) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID);
32 } 32 }
33 33
34 - public static Integer getUesrType(HttpServletRequest request) { 34 + public static Integer getUserType(HttpServletRequest request) {
35 return UserTypeEnum.ADMIN.getValue(); // TODO 芋艿:等后续优化 35 return UserTypeEnum.ADMIN.getValue(); // TODO 芋艿:等后续优化
36 } 36 }
37 37
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/permission/SysRoleMenuMapper.java
@@ -33,6 +33,14 @@ public interface SysRoleMenuMapper extends BaseMapperX&lt;SysRoleMenuDO&gt; { @@ -33,6 +33,14 @@ public interface SysRoleMenuMapper extends BaseMapperX&lt;SysRoleMenuDO&gt; {
33 .in("menu_id", menuIds)); 33 .in("menu_id", menuIds));
34 } 34 }
35 35
  36 + default void deleteListByMenuId(Long menuId) {
  37 + delete(new QueryWrapper<SysRoleMenuDO>().eq("menu_id", menuId));
  38 + }
  39 +
  40 + default void deleteListByRoleId(Long roleId) {
  41 + delete(new QueryWrapper<SysRoleMenuDO>().eq("role_id", roleId));
  42 + }
  43 +
36 default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) { 44 default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) {
37 return selectOne(new QueryWrapper<SysRoleMenuDO>().select("id") 45 return selectOne(new QueryWrapper<SysRoleMenuDO>().select("id")
38 .gt("update_time", maxUpdateTime).last("LIMIT 1")) != null; 46 .gt("update_time", maxUpdateTime).last("LIMIT 1")) != null;
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/permission/SysUserRoleMapper.java
1 package cn.iocoder.dashboard.modules.system.dal.mysql.permission; 1 package cn.iocoder.dashboard.modules.system.dal.mysql.permission;
2 2
  3 +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
3 import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysUserRoleDO; 4 import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysUserRoleDO;
4 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 5 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
5 -import com.baomidou.mybatisplus.core.mapper.BaseMapper;  
6 import org.apache.ibatis.annotations.Mapper; 6 import org.apache.ibatis.annotations.Mapper;
7 7
8 import java.util.Collection; 8 import java.util.Collection;
@@ -10,7 +10,7 @@ import java.util.List; @@ -10,7 +10,7 @@ import java.util.List;
10 import java.util.stream.Collectors; 10 import java.util.stream.Collectors;
11 11
12 @Mapper 12 @Mapper
13 -public interface SysUserRoleMapper extends BaseMapper<SysUserRoleDO> { 13 +public interface SysUserRoleMapper extends BaseMapperX<SysUserRoleDO> {
14 14
15 default List<SysUserRoleDO> selectListByUserId(Long userId) { 15 default List<SysUserRoleDO> selectListByUserId(Long userId) {
16 return selectList(new QueryWrapper<SysUserRoleDO>().eq("user_id", userId)); 16 return selectList(new QueryWrapper<SysUserRoleDO>().eq("user_id", userId));
@@ -32,4 +32,12 @@ public interface SysUserRoleMapper extends BaseMapper&lt;SysUserRoleDO&gt; { @@ -32,4 +32,12 @@ public interface SysUserRoleMapper extends BaseMapper&lt;SysUserRoleDO&gt; {
32 .in("role_id", roleIds)); 32 .in("role_id", roleIds));
33 } 33 }
34 34
  35 + default void deleteListByUserId(Long userId) {
  36 + delete(new QueryWrapper<SysUserRoleDO>().eq("user_id", userId));
  37 + }
  38 +
  39 + default void deleteListByRoleId(Long roleId) {
  40 + delete(new QueryWrapper<SysUserRoleDO>().eq("role_id", roleId));
  41 + }
  42 +
35 } 43 }
src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java
@@ -153,7 +153,6 @@ public class SysDeptServiceImpl implements SysDeptService { @@ -153,7 +153,6 @@ public class SysDeptServiceImpl implements SysDeptService {
153 } 153 }
154 // 删除部门 154 // 删除部门
155 deptMapper.deleteById(id); 155 deptMapper.deleteById(id);
156 - // TODO 需要处理下与角色的数据权限关联,等做数据权限一起处理下  
157 // 发送刷新消息 156 // 发送刷新消息
158 deptProducer.sendDeptRefreshMessage(); 157 deptProducer.sendDeptRefreshMessage();
159 } 158 }
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java
@@ -231,22 +231,41 @@ public class SysPermissionServiceImpl implements SysPermissionService { @@ -231,22 +231,41 @@ public class SysPermissionServiceImpl implements SysPermissionService {
231 } 231 }
232 232
233 @Override 233 @Override
  234 + @Transactional(rollbackFor = Exception.class)
234 public void processRoleDeleted(Long roleId) { 235 public void processRoleDeleted(Long roleId) {
235 - // TODO 实现我  
236 -// // 标记删除 RoleResource  
237 -// roleResourceMapper.deleteByRoleId(roleId);  
238 -// // 标记删除 AdminRole  
239 -// adminRoleMapper.deleteByRoleId(roleId); 236 + // 标记删除 UserRole
  237 + userRoleMapper.deleteListByRoleId(roleId);
  238 + // 标记删除 RoleMenu
  239 + roleMenuMapper.deleteListByRoleId(roleId);
  240 + // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了
  241 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  242 +
  243 + @Override
  244 + public void afterCommit() {
  245 + permissionProducer.sendRoleMenuRefreshMessage();
  246 + }
  247 +
  248 + });
240 } 249 }
241 250
242 @Override 251 @Override
  252 + @Transactional(rollbackFor = Exception.class)
243 public void processMenuDeleted(Long menuId) { 253 public void processMenuDeleted(Long menuId) {
244 - // TODO 实现我 254 + roleMenuMapper.deleteListByMenuId(menuId);
  255 + // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了
  256 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  257 +
  258 + @Override
  259 + public void afterCommit() {
  260 + permissionProducer.sendRoleMenuRefreshMessage();
  261 + }
  262 +
  263 + });
245 } 264 }
246 265
247 @Override 266 @Override
248 public void processUserDeleted(Long userId) { 267 public void processUserDeleted(Long userId) {
249 - // TODO 实现我 268 + userRoleMapper.deleteListByUserId(userId);
250 } 269 }
251 270
252 @Override 271 @Override
src/test/java/cn/iocoder/dashboard/BaseDbAndRedisUnitTest.java
@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
9 import org.redisson.spring.starter.RedissonAutoConfiguration; 9 import org.redisson.spring.starter.RedissonAutoConfiguration;
10 import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; 10 import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
11 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 11 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  12 +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
12 import org.springframework.boot.test.context.SpringBootTest; 13 import org.springframework.boot.test.context.SpringBootTest;
13 import org.springframework.context.annotation.Import; 14 import org.springframework.context.annotation.Import;
14 import org.springframework.test.context.ActiveProfiles; 15 import org.springframework.test.context.ActiveProfiles;
@@ -30,6 +31,7 @@ public class BaseDbAndRedisUnitTest { @@ -30,6 +31,7 @@ public class BaseDbAndRedisUnitTest {
30 // DB 配置类 31 // DB 配置类
31 DataSourceConfiguration.class, // 自己的 DB 配置类 32 DataSourceConfiguration.class, // 自己的 DB 配置类
32 DataSourceAutoConfiguration.class, // Spring DB 自动配置类 33 DataSourceAutoConfiguration.class, // Spring DB 自动配置类
  34 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
33 DruidDataSourceAutoConfigure.class, // Druid 自动配置类 35 DruidDataSourceAutoConfigure.class, // Druid 自动配置类
34 // MyBatis 配置类 36 // MyBatis 配置类
35 MybatisConfiguration.class, // 自己的 MyBatis 配置类 37 MybatisConfiguration.class, // 自己的 MyBatis 配置类
src/test/java/cn/iocoder/dashboard/BaseDbUnitTest.java
@@ -5,6 +5,7 @@ import cn.iocoder.dashboard.framework.mybatis.config.MybatisConfiguration; @@ -5,6 +5,7 @@ import cn.iocoder.dashboard.framework.mybatis.config.MybatisConfiguration;
5 import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; 5 import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
6 import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; 6 import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
7 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 7 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  8 +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
8 import org.springframework.boot.test.context.SpringBootTest; 9 import org.springframework.boot.test.context.SpringBootTest;
9 import org.springframework.context.annotation.Import; 10 import org.springframework.context.annotation.Import;
10 import org.springframework.test.context.ActiveProfiles; 11 import org.springframework.test.context.ActiveProfiles;
@@ -26,6 +27,7 @@ public class BaseDbUnitTest { @@ -26,6 +27,7 @@ public class BaseDbUnitTest {
26 // DB 配置类 27 // DB 配置类
27 DataSourceConfiguration.class, // 自己的 DB 配置类 28 DataSourceConfiguration.class, // 自己的 DB 配置类
28 DataSourceAutoConfiguration.class, // Spring DB 自动配置类 29 DataSourceAutoConfiguration.class, // Spring DB 自动配置类
  30 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
29 DruidDataSourceAutoConfigure.class, // Druid 自动配置类 31 DruidDataSourceAutoConfigure.class, // Druid 自动配置类
30 // MyBatis 配置类 32 // MyBatis 配置类
31 MybatisConfiguration.class, // 自己的 MyBatis 配置类 33 MybatisConfiguration.class, // 自己的 MyBatis 配置类
src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionServiceTest.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.service.permission;
  2 +
  3 +import cn.iocoder.dashboard.BaseDbUnitTest;
  4 +import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleMenuDO;
  5 +import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysUserRoleDO;
  6 +import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysRoleMenuMapper;
  7 +import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysUserRoleMapper;
  8 +import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysPermissionProducer;
  9 +import cn.iocoder.dashboard.modules.system.service.permission.impl.SysPermissionServiceImpl;
  10 +import org.junit.jupiter.api.Test;
  11 +import org.springframework.boot.test.mock.mockito.MockBean;
  12 +import org.springframework.context.annotation.Import;
  13 +
  14 +import javax.annotation.Resource;
  15 +import java.util.List;
  16 +
  17 +import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
  18 +import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
  19 +import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
  20 +import static org.junit.jupiter.api.Assertions.assertEquals;
  21 +import static org.mockito.Mockito.verify;
  22 +
  23 +@Import(SysPermissionServiceImpl.class)
  24 +public class SysPermissionServiceTest extends BaseDbUnitTest {
  25 +
  26 + @Resource
  27 + private SysPermissionServiceImpl permissionService;
  28 +
  29 + @Resource
  30 + private SysRoleMenuMapper roleMenuMapper;
  31 + @Resource
  32 + private SysUserRoleMapper userRoleMapper;
  33 +
  34 + @MockBean
  35 + private SysRoleService roleService;
  36 + @MockBean
  37 + private SysMenuService menuService;
  38 +
  39 + @MockBean
  40 + private SysPermissionProducer permissionProducer;
  41 +
  42 + @Test
  43 + public void testProcessRoleDeleted() {
  44 + // 准备参数
  45 + Long roleId = randomLongId();
  46 + // mock 数据 UserRole
  47 + SysUserRoleDO userRoleDO01 = randomPojo(SysUserRoleDO.class, o -> o.setRoleId(roleId)); // 被删除
  48 + userRoleMapper.insert(userRoleDO01);
  49 + SysUserRoleDO userRoleDO02 = randomPojo(SysUserRoleDO.class); // 不被删除
  50 + userRoleMapper.insert(userRoleDO02);
  51 + // mock 数据 RoleMenu
  52 + SysRoleMenuDO roleMenuDO01 = randomPojo(SysRoleMenuDO.class, o -> o.setRoleId(roleId)); // 被删除
  53 + roleMenuMapper.insert(roleMenuDO01);
  54 + SysRoleMenuDO roleMenuDO02 = randomPojo(SysRoleMenuDO.class); // 不被删除
  55 + roleMenuMapper.insert(roleMenuDO02);
  56 +
  57 + // 调用
  58 + permissionService.processRoleDeleted(roleId);
  59 + // 断言数据 RoleMenuDO
  60 + List<SysRoleMenuDO> dbRoleMenus = roleMenuMapper.selectList();
  61 + assertEquals(1, dbRoleMenus.size());
  62 + assertPojoEquals(dbRoleMenus.get(0), roleMenuDO02);
  63 + // 断言数据 UserRoleDO
  64 + List<SysUserRoleDO> dbUserRoles = userRoleMapper.selectList();
  65 + assertEquals(1, dbUserRoles.size());
  66 + assertPojoEquals(dbUserRoles.get(0), userRoleDO02);
  67 + // 断言调用
  68 + verify(permissionProducer).sendRoleMenuRefreshMessage();
  69 + }
  70 +
  71 + @Test
  72 + public void testProcessMenuDeleted() {
  73 + // 准备参数
  74 + Long menuId = randomLongId();
  75 + // mock 数据
  76 + SysRoleMenuDO roleMenuDO01 = randomPojo(SysRoleMenuDO.class, o -> o.setMenuId(menuId)); // 被删除
  77 + roleMenuMapper.insert(roleMenuDO01);
  78 + SysRoleMenuDO roleMenuDO02 = randomPojo(SysRoleMenuDO.class); // 不被删除
  79 + roleMenuMapper.insert(roleMenuDO02);
  80 +
  81 + // 调用
  82 + permissionService.processMenuDeleted(menuId);
  83 + // 断言数据
  84 + List<SysRoleMenuDO> dbRoleMenus = roleMenuMapper.selectList();
  85 + assertEquals(1, dbRoleMenus.size());
  86 + assertPojoEquals(dbRoleMenus.get(0), roleMenuDO02);
  87 + // 断言调用
  88 + verify(permissionProducer).sendRoleMenuRefreshMessage();
  89 + }
  90 +
  91 + @Test
  92 + public void testProcessUserDeleted() {
  93 + // 准备参数
  94 + Long userId = randomLongId();
  95 + // mock 数据
  96 + SysUserRoleDO userRoleDO01 = randomPojo(SysUserRoleDO.class, o -> o.setUserId(userId)); // 被删除
  97 + userRoleMapper.insert(userRoleDO01);
  98 + SysUserRoleDO userRoleDO02 = randomPojo(SysUserRoleDO.class); // 不被删除
  99 + userRoleMapper.insert(userRoleDO02);
  100 +
  101 + // 调用
  102 + permissionService.processUserDeleted(userId);
  103 + // 断言数据
  104 + List<SysUserRoleDO> dbUserRoles = userRoleMapper.selectList();
  105 + assertEquals(1, dbUserRoles.size());
  106 + assertPojoEquals(dbUserRoles.get(0), userRoleDO02);
  107 + }
  108 +
  109 +}
src/test/resources/sql/clean.sql
@@ -8,6 +8,7 @@ DELETE FROM &quot;sys_dict_data&quot;; @@ -8,6 +8,7 @@ DELETE FROM &quot;sys_dict_data&quot;;
8 DELETE FROM "sys_role"; 8 DELETE FROM "sys_role";
9 DELETE FROM "sys_role_menu"; 9 DELETE FROM "sys_role_menu";
10 DELETE FROM "sys_menu"; 10 DELETE FROM "sys_menu";
  11 +DELETE FROM "sys_user_role";
11 DELETE FROM "sys_dict_type"; 12 DELETE FROM "sys_dict_type";
12 DELETE FROM "sys_user_session"; 13 DELETE FROM "sys_user_session";
13 DELETE FROM "sys_post"; 14 DELETE FROM "sys_post";
src/test/resources/sql/create_tables.sql
@@ -113,6 +113,18 @@ CREATE TABLE IF NOT EXISTS &quot;sys_menu&quot; ( @@ -113,6 +113,18 @@ CREATE TABLE IF NOT EXISTS &quot;sys_menu&quot; (
113 PRIMARY KEY ("id") 113 PRIMARY KEY ("id")
114 ) COMMENT '菜单权限表'; 114 ) COMMENT '菜单权限表';
115 115
  116 +CREATE TABLE IF NOT EXISTS "sys_user_role" (
  117 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  118 + "user_id" bigint NOT NULL,
  119 + "role_id" bigint NOT NULL,
  120 + "creator" varchar(64) DEFAULT '',
  121 + "create_time" timestamp DEFAULT NULL,
  122 + "updater" varchar(64) DEFAULT '',
  123 + "update_time" timestamp DEFAULT NULL,
  124 + "deleted" bit DEFAULT FALSE,
  125 + PRIMARY KEY ("id")
  126 +) COMMENT '用户和角色关联表';
  127 +
116 CREATE TABLE IF NOT EXISTS "sys_dict_type" ( 128 CREATE TABLE IF NOT EXISTS "sys_dict_type" (
117 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, 129 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
118 "name" varchar(100) NOT NULL DEFAULT '', 130 "name" varchar(100) NOT NULL DEFAULT '',
@@ -297,4 +309,4 @@ create table &quot;inf_api_error_log&quot; ( @@ -297,4 +309,4 @@ create table &quot;inf_api_error_log&quot; (
297 "update_time" timestamp not null default current_timestamp, 309 "update_time" timestamp not null default current_timestamp,
298 "deleted" bit not null default false, 310 "deleted" bit not null default false,
299 primary key ("id") 311 primary key ("id")
300 -) comment '系统异常日志';  
301 \ No newline at end of file 312 \ No newline at end of file
  313 +) comment '系统异常日志';