Commit b0855cc626d2b9eb4495ea9e2d996df11d8dd090
1 parent
f9b15fe7
实现 DataPermissionRuleFactoryImpl,并增加相关单测
Showing
6 changed files
with
284 additions
and
15 deletions
yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationInterceptor.java
| @@ -34,7 +34,7 @@ public class DataPermissionAnnotationInterceptor implements MethodInterceptor { | @@ -34,7 +34,7 @@ public class DataPermissionAnnotationInterceptor implements MethodInterceptor { | ||
| 34 | // 入栈 | 34 | // 入栈 |
| 35 | DataPermission dataPermission = this.findAnnotation(methodInvocation); | 35 | DataPermission dataPermission = this.findAnnotation(methodInvocation); |
| 36 | if (dataPermission != null) { | 36 | if (dataPermission != null) { |
| 37 | - DataPermissionContextHolder.push(dataPermission); | 37 | + DataPermissionContextHolder.add(dataPermission); |
| 38 | } | 38 | } |
| 39 | try { | 39 | try { |
| 40 | // 执行逻辑 | 40 | // 执行逻辑 |
| @@ -42,7 +42,7 @@ public class DataPermissionAnnotationInterceptor implements MethodInterceptor { | @@ -42,7 +42,7 @@ public class DataPermissionAnnotationInterceptor implements MethodInterceptor { | ||
| 42 | } finally { | 42 | } finally { |
| 43 | // 出栈 | 43 | // 出栈 |
| 44 | if (dataPermission != null) { | 44 | if (dataPermission != null) { |
| 45 | - DataPermissionContextHolder.poll(); | 45 | + DataPermissionContextHolder.remove(); |
| 46 | } | 46 | } |
| 47 | } | 47 | } |
| 48 | } | 48 | } |
yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolder.java
| @@ -3,8 +3,8 @@ package cn.iocoder.yudao.framework.datapermission.core.aop; | @@ -3,8 +3,8 @@ package cn.iocoder.yudao.framework.datapermission.core.aop; | ||
| 3 | import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | 3 | import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; |
| 4 | import com.alibaba.ttl.TransmittableThreadLocal; | 4 | import com.alibaba.ttl.TransmittableThreadLocal; |
| 5 | 5 | ||
| 6 | -import java.util.ArrayDeque; | ||
| 7 | -import java.util.Deque; | 6 | +import java.util.LinkedList; |
| 7 | +import java.util.List; | ||
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| 10 | * {@link DataPermission} 注解的 Context 上下文 | 10 | * {@link DataPermission} 注解的 Context 上下文 |
| @@ -13,16 +13,19 @@ import java.util.Deque; | @@ -13,16 +13,19 @@ import java.util.Deque; | ||
| 13 | */ | 13 | */ |
| 14 | public class DataPermissionContextHolder { | 14 | public class DataPermissionContextHolder { |
| 15 | 15 | ||
| 16 | - private static final ThreadLocal<Deque<DataPermission>> DATA_PERMISSIONS = | ||
| 17 | - TransmittableThreadLocal.withInitial(ArrayDeque::new); | 16 | + /** |
| 17 | + * 使用 List 的原因,可能存在方法的嵌套调用 | ||
| 18 | + */ | ||
| 19 | + private static final ThreadLocal<LinkedList<DataPermission>> DATA_PERMISSIONS = | ||
| 20 | + TransmittableThreadLocal.withInitial(LinkedList::new); | ||
| 18 | 21 | ||
| 19 | /** | 22 | /** |
| 20 | * 获得当前的 DataPermission 注解 | 23 | * 获得当前的 DataPermission 注解 |
| 21 | * | 24 | * |
| 22 | * @return DataPermission 注解 | 25 | * @return DataPermission 注解 |
| 23 | */ | 26 | */ |
| 24 | - public static DataPermission peek() { | ||
| 25 | - return DATA_PERMISSIONS.get().remove(); | 27 | + public static DataPermission get() { |
| 28 | + return DATA_PERMISSIONS.get().peekLast(); | ||
| 26 | } | 29 | } |
| 27 | 30 | ||
| 28 | /** | 31 | /** |
| @@ -30,8 +33,8 @@ public class DataPermissionContextHolder { | @@ -30,8 +33,8 @@ public class DataPermissionContextHolder { | ||
| 30 | * | 33 | * |
| 31 | * @param dataPermission DataPermission 注解 | 34 | * @param dataPermission DataPermission 注解 |
| 32 | */ | 35 | */ |
| 33 | - public static void push(DataPermission dataPermission) { | ||
| 34 | - DATA_PERMISSIONS.get().push(dataPermission); | 36 | + public static void add(DataPermission dataPermission) { |
| 37 | + DATA_PERMISSIONS.get().addLast(dataPermission); | ||
| 35 | } | 38 | } |
| 36 | 39 | ||
| 37 | /** | 40 | /** |
| @@ -39,13 +42,31 @@ public class DataPermissionContextHolder { | @@ -39,13 +42,31 @@ public class DataPermissionContextHolder { | ||
| 39 | * | 42 | * |
| 40 | * @return DataPermission 注解 | 43 | * @return DataPermission 注解 |
| 41 | */ | 44 | */ |
| 42 | - public static DataPermission poll() { | ||
| 43 | - DataPermission dataPermission = DATA_PERMISSIONS.get().poll(); | 45 | + public static DataPermission remove() { |
| 46 | + DataPermission dataPermission = DATA_PERMISSIONS.get().removeLast(); | ||
| 44 | // 无元素时,清空 ThreadLocal | 47 | // 无元素时,清空 ThreadLocal |
| 45 | - if (dataPermission == null) { | 48 | + if (DATA_PERMISSIONS.get().isEmpty()) { |
| 46 | DATA_PERMISSIONS.remove(); | 49 | DATA_PERMISSIONS.remove(); |
| 47 | } | 50 | } |
| 48 | return dataPermission; | 51 | return dataPermission; |
| 49 | } | 52 | } |
| 50 | 53 | ||
| 54 | + /** | ||
| 55 | + * 获得所有 DataPermission | ||
| 56 | + * | ||
| 57 | + * @return DataPermission 队列 | ||
| 58 | + */ | ||
| 59 | + public static List<DataPermission> getAll() { | ||
| 60 | + return DATA_PERMISSIONS.get(); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * 清空上下文 | ||
| 65 | + * | ||
| 66 | + * 目前仅仅用于单测 | ||
| 67 | + */ | ||
| 68 | + public static void clear() { | ||
| 69 | + DATA_PERMISSIONS.remove(); | ||
| 70 | + } | ||
| 71 | + | ||
| 51 | } | 72 | } |
yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImpl.java
| 1 | package cn.iocoder.yudao.framework.datapermission.core.rule; | 1 | package cn.iocoder.yudao.framework.datapermission.core.rule; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.util.ArrayUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | ||
| 6 | +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; | ||
| 3 | import lombok.RequiredArgsConstructor; | 7 | import lombok.RequiredArgsConstructor; |
| 4 | 8 | ||
| 9 | +import java.util.Collections; | ||
| 5 | import java.util.List; | 10 | import java.util.List; |
| 11 | +import java.util.stream.Collectors; | ||
| 6 | 12 | ||
| 13 | +/** | ||
| 14 | + * 默认的 DataPermissionRuleFactoryImpl 实现类 | ||
| 15 | + * 支持通过 {@link DataPermissionContextHolder} 过滤数据权限 | ||
| 16 | + * | ||
| 17 | + * @author 芋道源码 | ||
| 18 | + */ | ||
| 7 | @RequiredArgsConstructor | 19 | @RequiredArgsConstructor |
| 8 | public class DataPermissionRuleFactoryImpl implements DataPermissionRuleFactory { | 20 | public class DataPermissionRuleFactoryImpl implements DataPermissionRuleFactory { |
| 9 | 21 | ||
| @@ -17,9 +29,34 @@ public class DataPermissionRuleFactoryImpl implements DataPermissionRuleFactory | @@ -17,9 +29,34 @@ public class DataPermissionRuleFactoryImpl implements DataPermissionRuleFactory | ||
| 17 | return rules; | 29 | return rules; |
| 18 | } | 30 | } |
| 19 | 31 | ||
| 20 | - @Override | 32 | + @Override // mappedStatementId 参数,暂时没有用。以后,可以基于 mappedStatementId + DataPermission 进行缓存 |
| 21 | public List<DataPermissionRule> getDataPermissionRule(String mappedStatementId) { | 33 | public List<DataPermissionRule> getDataPermissionRule(String mappedStatementId) { |
| 22 | - return null; | 34 | + // 1. 无数据权限 |
| 35 | + if (CollUtil.isEmpty(rules)) { | ||
| 36 | + return Collections.emptyList(); | ||
| 37 | + } | ||
| 38 | + // 2. 未配置,则默认开启 | ||
| 39 | + DataPermission dataPermission = DataPermissionContextHolder.get(); | ||
| 40 | + if (dataPermission == null) { | ||
| 41 | + return rules; | ||
| 42 | + } | ||
| 43 | + // 3. 已配置,但禁用 | ||
| 44 | + if (!dataPermission.enable()) { | ||
| 45 | + return Collections.emptyList(); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + // 4. 已配置,只选择部分规则 | ||
| 49 | + if (ArrayUtil.isNotEmpty(dataPermission.includeRules())) { | ||
| 50 | + return rules.stream().filter(rule -> ArrayUtil.contains(dataPermission.includeRules(), rule.getClass())) | ||
| 51 | + .collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询 | ||
| 52 | + } | ||
| 53 | + // 5. 已配置,只排除部分规则 | ||
| 54 | + if (ArrayUtil.isNotEmpty(dataPermission.excludeRules())) { | ||
| 55 | + return rules.stream().filter(rule -> !ArrayUtil.contains(dataPermission.excludeRules(), rule.getClass())) | ||
| 56 | + .collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询 | ||
| 57 | + } | ||
| 58 | + // 6. 已配置,全部规则 | ||
| 59 | + return rules; | ||
| 23 | } | 60 | } |
| 24 | 61 | ||
| 25 | } | 62 | } |
yudao-framework/yudao-spring-boot-starter-data-permission/src/test/resources/META-INF/spring.factories renamed to yudao-framework/yudao-spring-boot-starter-data-permission/src/main/resources/META-INF/spring.factories
yudao-framework/yudao-spring-boot-starter-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolderTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.datapermission.core.aop; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | ||
| 4 | +import org.junit.jupiter.api.BeforeEach; | ||
| 5 | +import org.junit.jupiter.api.Test; | ||
| 6 | + | ||
| 7 | +import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 8 | +import static org.junit.jupiter.api.Assertions.assertSame; | ||
| 9 | +import static org.mockito.Mockito.mock; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * {@link DataPermissionContextHolder} 的单元测试 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +class DataPermissionContextHolderTest { | ||
| 17 | + | ||
| 18 | + @BeforeEach | ||
| 19 | + public void setUp() { | ||
| 20 | + DataPermissionContextHolder.clear(); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + @Test | ||
| 24 | + public void testGet() { | ||
| 25 | + // mock 方法 | ||
| 26 | + DataPermission dataPermission01 = mock(DataPermission.class); | ||
| 27 | + DataPermissionContextHolder.add(dataPermission01); | ||
| 28 | + DataPermission dataPermission02 = mock(DataPermission.class); | ||
| 29 | + DataPermissionContextHolder.add(dataPermission02); | ||
| 30 | + | ||
| 31 | + // 调用 | ||
| 32 | + DataPermission result = DataPermissionContextHolder.get(); | ||
| 33 | + // 断言 | ||
| 34 | + assertSame(result, dataPermission02); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + @Test | ||
| 38 | + public void testPush() { | ||
| 39 | + // 调用 | ||
| 40 | + DataPermission dataPermission01 = mock(DataPermission.class); | ||
| 41 | + DataPermissionContextHolder.add(dataPermission01); | ||
| 42 | + DataPermission dataPermission02 = mock(DataPermission.class); | ||
| 43 | + DataPermissionContextHolder.add(dataPermission02); | ||
| 44 | + // 断言 | ||
| 45 | + DataPermission first = DataPermissionContextHolder.getAll().get(0); | ||
| 46 | + DataPermission second = DataPermissionContextHolder.getAll().get(1); | ||
| 47 | + assertSame(dataPermission01, first); | ||
| 48 | + assertSame(dataPermission02, second); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @Test | ||
| 52 | + public void testRemove() { | ||
| 53 | + // mock 方法 | ||
| 54 | + DataPermission dataPermission01 = mock(DataPermission.class); | ||
| 55 | + DataPermissionContextHolder.add(dataPermission01); | ||
| 56 | + DataPermission dataPermission02 = mock(DataPermission.class); | ||
| 57 | + DataPermissionContextHolder.add(dataPermission02); | ||
| 58 | + | ||
| 59 | + // 调用 | ||
| 60 | + DataPermission result = DataPermissionContextHolder.remove(); | ||
| 61 | + // 断言 | ||
| 62 | + assertSame(result, dataPermission02); | ||
| 63 | + assertEquals(1, DataPermissionContextHolder.getAll().size()); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | +} |
yudao-framework/yudao-spring-boot-starter-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImplTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.datapermission.core.rule; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | ||
| 4 | +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; | ||
| 5 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | ||
| 6 | +import net.sf.jsqlparser.expression.Alias; | ||
| 7 | +import net.sf.jsqlparser.expression.Expression; | ||
| 8 | +import org.junit.jupiter.api.BeforeEach; | ||
| 9 | +import org.junit.jupiter.api.Test; | ||
| 10 | +import org.mockito.InjectMocks; | ||
| 11 | +import org.mockito.Spy; | ||
| 12 | +import org.springframework.core.annotation.AnnotationUtils; | ||
| 13 | + | ||
| 14 | +import java.util.Arrays; | ||
| 15 | +import java.util.List; | ||
| 16 | +import java.util.Set; | ||
| 17 | + | ||
| 18 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; | ||
| 19 | +import static org.junit.jupiter.api.Assertions.*; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * {@link DataPermissionRuleFactoryImpl} 单元测试 | ||
| 23 | + * | ||
| 24 | + * @author 芋道源码 | ||
| 25 | + */ | ||
| 26 | +class DataPermissionRuleFactoryImplTest extends BaseMockitoUnitTest { | ||
| 27 | + | ||
| 28 | + @InjectMocks | ||
| 29 | + private DataPermissionRuleFactoryImpl dataPermissionRuleFactory; | ||
| 30 | + | ||
| 31 | + @Spy | ||
| 32 | + private List<DataPermissionRule> rules = Arrays.asList(new DataPermissionRule01(), | ||
| 33 | + new DataPermissionRule02()); | ||
| 34 | + | ||
| 35 | + @BeforeEach | ||
| 36 | + public void setUp() { | ||
| 37 | + DataPermissionContextHolder.clear(); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + @Test | ||
| 41 | + public void testGetDataPermissionRule_02() { | ||
| 42 | + // 准备参数 | ||
| 43 | + String mappedStatementId = randomString(); | ||
| 44 | + | ||
| 45 | + // 调用 | ||
| 46 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | ||
| 47 | + // 断言 | ||
| 48 | + assertSame(rules, result); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @Test | ||
| 52 | + public void testGetDataPermissionRule_03() { | ||
| 53 | + // 准备参数 | ||
| 54 | + String mappedStatementId = randomString(); | ||
| 55 | + // mock 方法 | ||
| 56 | + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass03.class, DataPermission.class)); | ||
| 57 | + | ||
| 58 | + // 调用 | ||
| 59 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | ||
| 60 | + // 断言 | ||
| 61 | + assertTrue(result.isEmpty()); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + @Test | ||
| 65 | + public void testGetDataPermissionRule_04() { | ||
| 66 | + // 准备参数 | ||
| 67 | + String mappedStatementId = randomString(); | ||
| 68 | + // mock 方法 | ||
| 69 | + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass04.class, DataPermission.class)); | ||
| 70 | + | ||
| 71 | + // 调用 | ||
| 72 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | ||
| 73 | + // 断言 | ||
| 74 | + assertEquals(1, result.size()); | ||
| 75 | + assertEquals(DataPermissionRule01.class, result.get(0).getClass()); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @Test | ||
| 79 | + public void testGetDataPermissionRule_05() { | ||
| 80 | + // 准备参数 | ||
| 81 | + String mappedStatementId = randomString(); | ||
| 82 | + // mock 方法 | ||
| 83 | + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass05.class, DataPermission.class)); | ||
| 84 | + | ||
| 85 | + // 调用 | ||
| 86 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | ||
| 87 | + // 断言 | ||
| 88 | + assertEquals(1, result.size()); | ||
| 89 | + assertEquals(DataPermissionRule02.class, result.get(0).getClass()); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + @Test | ||
| 93 | + public void testGetDataPermissionRule_06() { | ||
| 94 | + // 准备参数 | ||
| 95 | + String mappedStatementId = randomString(); | ||
| 96 | + // mock 方法 | ||
| 97 | + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass06.class, DataPermission.class)); | ||
| 98 | + | ||
| 99 | + // 调用 | ||
| 100 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | ||
| 101 | + // 断言 | ||
| 102 | + assertSame(rules, result); | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + @DataPermission(enable = false) | ||
| 106 | + static class TestClass03 {} | ||
| 107 | + | ||
| 108 | + @DataPermission(includeRules = DataPermissionRule01.class) | ||
| 109 | + static class TestClass04 {} | ||
| 110 | + | ||
| 111 | + @DataPermission(excludeRules = DataPermissionRule01.class) | ||
| 112 | + static class TestClass05 {} | ||
| 113 | + | ||
| 114 | + @DataPermission | ||
| 115 | + static class TestClass06 {} | ||
| 116 | + | ||
| 117 | + static class DataPermissionRule01 implements DataPermissionRule { | ||
| 118 | + | ||
| 119 | + @Override | ||
| 120 | + public Set<String> getTableNames() { | ||
| 121 | + return null; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + @Override | ||
| 125 | + public Expression getExpression(String tableName, Alias tableAlias) { | ||
| 126 | + return null; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + static class DataPermissionRule02 implements DataPermissionRule { | ||
| 132 | + | ||
| 133 | + @Override | ||
| 134 | + public Set<String> getTableNames() { | ||
| 135 | + return null; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + @Override | ||
| 139 | + public Expression getExpression(String tableName, Alias tableAlias) { | ||
| 140 | + return null; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | +} |