调整 SecurityPermissionFrameworkService 的实现,完善 PermissionServiceTest 的单元测试

pull/2/head
YunaiV 2022-05-13 00:24:10 +08:00
parent 49b4eedfc0
commit 5794780c4e
18 changed files with 246 additions and 88 deletions

View File

@ -34,6 +34,13 @@
<artifactId>yudao-spring-boot-starter-mybatis</artifactId> <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
</dependency> </dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-system-api</artifactId> <!-- 需要使用它,进行数据权限的获取 -->
<version>${revision}</version>
</dependency>
<!-- Test 测试相关 --> <!-- Test 测试相关 -->
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.framework.datapermission.config; package cn.iocoder.yudao.framework.datapermission.config;
import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRule; import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule;
import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRuleCustomizer; import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -18,14 +18,14 @@ import java.util.List;
*/ */
@Configuration @Configuration
@ConditionalOnClass(LoginUser.class) @ConditionalOnClass(LoginUser.class)
@ConditionalOnBean(value = {DeptDataPermissionFrameworkService.class, DeptDataPermissionRuleCustomizer.class}) @ConditionalOnBean(value = {PermissionApi.class, DeptDataPermissionRuleCustomizer.class})
public class YudaoDeptDataPermissionAutoConfiguration { public class YudaoDeptDataPermissionAutoConfiguration {
@Bean @Bean
public DeptDataPermissionRule deptDataPermissionRule(DeptDataPermissionFrameworkService service, public DeptDataPermissionRule deptDataPermissionRule(PermissionApi permissionApi,
List<DeptDataPermissionRuleCustomizer> customizers) { List<DeptDataPermissionRuleCustomizer> customizers) {
// 创建 DeptDataPermissionRule 对象 // 创建 DeptDataPermissionRule 对象
DeptDataPermissionRule rule = new DeptDataPermissionRule(service); DeptDataPermissionRule rule = new DeptDataPermissionRule(permissionApi);
// 补全表配置 // 补全表配置
customizers.forEach(customizer -> customizer.customize(rule)); customizers.forEach(customizer -> customizer.customize(rule));
return rule; return rule;

View File

@ -1,21 +0,0 @@
package cn.iocoder.yudao.framework.datapermission.core.dept.service;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
/**
* Framework Service
* SysPermissionServiceImpl
*
* @author
*/
public interface DeptDataPermissionFrameworkService {
/**
*
*
* @param userId
* @return
*/
DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.datapermission.core.dept.rule; package cn.iocoder.yudao.framework.datapermission.core.rule.dept;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
@ -6,13 +6,13 @@ import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -25,7 +25,10 @@ import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression; import net.sf.jsqlparser.expression.operators.relational.InExpression;
import java.util.*; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/** /**
* {@link DataPermissionRule} * {@link DataPermissionRule}
@ -58,7 +61,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
static final Expression EXPRESSION_NULL = new NullValue(); static final Expression EXPRESSION_NULL = new NullValue();
private final DeptDataPermissionFrameworkService deptDataPermissionService; private final PermissionApi permissionApi;
/** /**
* *
@ -102,7 +105,7 @@ public class DeptDataPermissionRule implements DataPermissionRule {
DeptDataPermissionRespDTO deptDataPermission = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class); DeptDataPermissionRespDTO deptDataPermission = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class);
// 从上下文中拿不到,则调用逻辑进行获取 // 从上下文中拿不到,则调用逻辑进行获取
if (deptDataPermission == null) { if (deptDataPermission == null) {
deptDataPermission = deptDataPermissionService.getDeptDataPermission(loginUser.getId()); deptDataPermission = permissionApi.getDeptDataPermission(loginUser.getId());
if (deptDataPermission == null) { if (deptDataPermission == null) {
log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser)); log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser));
throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限", throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限",

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.framework.datapermission.core.dept.rule; package cn.iocoder.yudao.framework.datapermission.core.rule.dept;
/** /**
* {@link DeptDataPermissionRule} * {@link DeptDataPermissionRule}

View File

@ -3,4 +3,4 @@
* *
* @author * @author
*/ */
package cn.iocoder.yudao.framework.datapermission.core.dept; package cn.iocoder.yudao.framework.datapermission.core.rule.dept;

View File

@ -1,11 +1,11 @@
package cn.iocoder.yudao.framework.datapermission.core.dept.rule; package cn.iocoder.yudao.framework.datapermission.core.rule.dept;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService; import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
@ -19,7 +19,7 @@ import org.mockito.MockedStatic;
import java.util.Map; import java.util.Map;
import static cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRule.EXPRESSION_NULL; import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRule.EXPRESSION_NULL;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -38,7 +38,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
private DeptDataPermissionRule rule; private DeptDataPermissionRule rule;
@Mock @Mock
private DeptDataPermissionFrameworkService deptDataPermissionFrameworkService; private PermissionApi permissionApi;
@BeforeEach @BeforeEach
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -95,7 +95,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
// mock 方法DeptDataPermissionRespDTO // mock 方法DeptDataPermissionRespDTO
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO().setAll(true); DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO().setAll(true);
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
// 调用 // 调用
Expression expression = rule.getExpression(tableName, tableAlias); Expression expression = rule.getExpression(tableName, tableAlias);
@ -118,7 +118,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
// mock 方法DeptDataPermissionRespDTO // mock 方法DeptDataPermissionRespDTO
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO(); DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO();
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
// 调用 // 调用
Expression expression = rule.getExpression(tableName, tableAlias); Expression expression = rule.getExpression(tableName, tableAlias);
@ -142,7 +142,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
// mock 方法DeptDataPermissionRespDTO // mock 方法DeptDataPermissionRespDTO
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
.setDeptIds(SetUtils.asSet(10L, 20L)).setSelf(true); .setDeptIds(SetUtils.asSet(10L, 20L)).setSelf(true);
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
// 调用 // 调用
Expression expression = rule.getExpression(tableName, tableAlias); Expression expression = rule.getExpression(tableName, tableAlias);
@ -166,7 +166,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
// mock 方法DeptDataPermissionRespDTO // mock 方法DeptDataPermissionRespDTO
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
.setSelf(true); .setSelf(true);
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
// 添加 user 字段配置 // 添加 user 字段配置
rule.addUserColumn("t_user", "id"); rule.addUserColumn("t_user", "id");
@ -192,7 +192,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
// mock 方法DeptDataPermissionRespDTO // mock 方法DeptDataPermissionRespDTO
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
.setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)); .setDeptIds(CollUtil.newLinkedHashSet(10L, 20L));
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
// 添加 dept 字段配置 // 添加 dept 字段配置
rule.addDeptColumn("t_user", "dept_id"); rule.addDeptColumn("t_user", "dept_id");
@ -218,7 +218,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
// mock 方法DeptDataPermissionRespDTO // mock 方法DeptDataPermissionRespDTO
DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
.setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)).setSelf(true); .setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)).setSelf(true);
when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
// 添加 user 字段配置 // 添加 user 字段配置
rule.addUserColumn("t_user", "id"); rule.addUserColumn("t_user", "id");
// 添加 dept 字段配置 // 添加 dept 字段配置

View File

@ -5,8 +5,11 @@ import cn.iocoder.yudao.framework.security.core.context.TransmittableThreadLocal
import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter; import cn.iocoder.yudao.framework.security.core.filter.TokenAuthenticationFilter;
import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl;
import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl;
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkServiceImpl;
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
import cn.iocoder.yudao.module.system.api.auth.OAuth2TokenApi; import cn.iocoder.yudao.module.system.api.auth.OAuth2TokenApi;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -78,6 +81,11 @@ public class YudaoSecurityAutoConfiguration {
return new TokenAuthenticationFilter(securityProperties, globalExceptionHandler, oauth2TokenApi); return new TokenAuthenticationFilter(securityProperties, globalExceptionHandler, oauth2TokenApi);
} }
@Bean("ss") // 使用 Spring Security 的缩写,方便食用
public SecurityFrameworkService securityFrameworkService(PermissionApi permissionApi) {
return new SecurityFrameworkServiceImpl(permissionApi);
}
/** /**
* {@link SecurityContextHolder#setStrategyName(String)} * {@link SecurityContextHolder#setStrategyName(String)}
* 使 {@link TransmittableThreadLocalSecurityContextHolderStrategy} Security * 使 {@link TransmittableThreadLocalSecurityContextHolderStrategy} Security

View File

@ -1,11 +1,11 @@
package cn.iocoder.yudao.framework.security.core.service; package cn.iocoder.yudao.framework.security.core.service;
/** /**
* Security Permission Service security * Security Service
* *
* @author * @author
*/ */
public interface SecurityPermissionFrameworkService { public interface SecurityFrameworkService {
/** /**
* *

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.framework.security.core.service;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import lombok.AllArgsConstructor;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/**
* {@link SecurityFrameworkService}
*
* @author
*/
@AllArgsConstructor
public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
private final PermissionApi permissionApi;
@Override
public boolean hasPermission(String permission) {
return hasAnyPermissions(permission);
}
@Override
public boolean hasAnyPermissions(String... permissions) {
return permissionApi.hasAnyPermissions(getLoginUserId(), permissions);
}
@Override
public boolean hasRole(String role) {
return hasAnyRoles(role);
}
@Override
public boolean hasAnyRoles(String... roles) {
return permissionApi.hasAnyRoles(getLoginUserId(), roles);
}
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.api.permission; package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Set;
@ -18,4 +20,30 @@ public interface PermissionApi {
*/ */
Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds); Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds);
/**
*
*
* @param userId
* @param permissions
* @return
*/
boolean hasAnyPermissions(Long userId, String... permissions);
/**
*
*
* @param userId
* @param roles
* @return
*/
boolean hasAnyRoles(Long userId, String... roles);
/**
*
*
* @param userId
* @return
*/
DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.api.permission; package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -23,4 +24,19 @@ public class PermissionApiImpl implements PermissionApi {
return permissionService.getUserRoleIdListByRoleIds(roleIds); return permissionService.getUserRoleIdListByRoleIds(roleIds);
} }
@Override
public boolean hasAnyPermissions(Long userId, String... permissions) {
return permissionService.hasAnyPermissions(userId, permissions);
}
@Override
public boolean hasAnyRoles(Long userId, String... roles) {
return permissionService.hasAnyRoles(userId, roles);
}
@Override
public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) {
return permissionService.getDeptDataPermission(userId);
}
} }

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.framework.datapermission.config;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRuleCustomizer; import cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataPermissionRuleCustomizer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;

View File

@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.system.service.permission; package cn.iocoder.yudao.module.system.service.permission;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.security.core.service.SecurityPermissionFrameworkService;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -16,7 +15,7 @@ import java.util.Set;
* *
* @author * @author
*/ */
public interface PermissionService extends SecurityPermissionFrameworkService, DeptDataPermissionFrameworkService { public interface PermissionService {
/** /**
* *
@ -115,4 +114,29 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D
*/ */
void processUserDeleted(Long userId); void processUserDeleted(Long userId);
/**
*
*
* @param userId
* @param permissions
* @return
*/
boolean hasAnyPermissions(Long userId, String... permissions);
/**
*
*
* @param roles
* @return
*/
boolean hasAnyRoles(Long userId, String... roles);
/**
*
*
* @param userId
* @return
*/
DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
} }

View File

@ -8,7 +8,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
@ -45,7 +45,6 @@ import java.util.function.Supplier;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static java.util.Collections.singleton; import static java.util.Collections.singleton;
/** /**
@ -53,7 +52,7 @@ import static java.util.Collections.singleton;
* *
* @author * @author
*/ */
@Service("ss") // 使用 Spring Security 的缩写,方便食用 @Service
@Slf4j @Slf4j
public class PermissionServiceImpl implements PermissionService { public class PermissionServiceImpl implements PermissionService {
@ -71,7 +70,7 @@ public class PermissionServiceImpl implements PermissionService {
* volatile * volatile
*/ */
@Getter @Getter
@Setter // 单元测试 @Setter // 单元测试需要
private volatile Multimap<Long, Long> roleMenuCache; private volatile Multimap<Long, Long> roleMenuCache;
/** /**
* *
@ -81,6 +80,7 @@ public class PermissionServiceImpl implements PermissionService {
* volatile * volatile
*/ */
@Getter @Getter
@Setter // 单元测试需要
private volatile Multimap<Long, Long> menuRoleCache; private volatile Multimap<Long, Long> menuRoleCache;
/** /**
* RoleMenu * RoleMenu
@ -399,19 +399,14 @@ public class PermissionServiceImpl implements PermissionService {
} }
@Override @Override
public boolean hasPermission(String permission) { public boolean hasAnyPermissions(Long userId, String... permissions) {
return hasAnyPermissions(permission);
}
@Override
public boolean hasAnyPermissions(String... permissions) {
// 如果为空,说明已经有权限 // 如果为空,说明已经有权限
if (ArrayUtil.isEmpty(permissions)) { if (ArrayUtil.isEmpty(permissions)) {
return true; return true;
} }
// 获得当前登录的角色。如果为空,说明没有权限 // 获得当前登录的角色。如果为空,说明没有权限
Set<Long> roleIds = getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
if (CollUtil.isEmpty(roleIds)) { if (CollUtil.isEmpty(roleIds)) {
return false; return false;
} }
@ -434,19 +429,14 @@ public class PermissionServiceImpl implements PermissionService {
} }
@Override @Override
public boolean hasRole(String role) { public boolean hasAnyRoles(Long userId, String... roles) {
return hasAnyRoles(role);
}
@Override
public boolean hasAnyRoles(String... roles) {
// 如果为空,说明已经有权限 // 如果为空,说明已经有权限
if (ArrayUtil.isEmpty(roles)) { if (ArrayUtil.isEmpty(roles)) {
return true; return true;
} }
// 获得当前登录的角色。如果为空,说明没有权限 // 获得当前登录的角色。如果为空,说明没有权限
Set<Long> roleIds = getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
if (CollUtil.isEmpty(roleIds)) { if (CollUtil.isEmpty(roleIds)) {
return false; return false;
} }

View File

@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.service.common.CaptchaService; import cn.iocoder.yudao.module.system.service.common.CaptchaService;
import cn.iocoder.yudao.module.system.service.logger.LoginLogService; import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.social.SocialUserService; import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -49,6 +50,8 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
private SmsCodeApi smsCodeApi; private SmsCodeApi smsCodeApi;
@MockBean @MockBean
private OAuth2TokenService oauth2TokenService; private OAuth2TokenService oauth2TokenService;
@MockBean
private MemberService memberService;
@MockBean @MockBean
private Validator validator; private Validator validator;

View File

@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
@ -359,22 +359,84 @@ public class PermissionServiceTest extends BaseDbUnitTest {
verify(permissionProducer).sendUserRoleRefreshMessage(); verify(permissionProducer).sendUserRoleRefreshMessage();
} }
// @Test @Test
// public void testHasAnyRoles_superAdmin() { public void testHasAnyPermissions_superAdmin() {
// // 准备参数 // 准备参数
// String[] roles = new String[]{"yunai", "tudou"}; Long userId = 1L;
// // mock 方法 String[] roles = new String[]{"system:user:query", "system:user:create"};
// List<RoleDO> roleList = singletonList(randomPojo(RoleDO.class, o -> o.setId(100L))); // mock 用户与角色的缓存
// when(roleService.getRolesFromCache(eq(roleIds))).thenReturn(roleList); permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(100L)).build());
// when(roleService.hasAnySuperAdmin(same(roleList))).thenReturn(true); RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L)
// List<MenuDO> menuList = randomPojoList(MenuDO.class); .setStatus(CommonStatusEnum.ENABLE.getStatus()));
// when(menuService.getMenuListFromCache(eq(menuTypes), eq(menusStatuses))).thenReturn(menuList); when(roleService.getRoleFromCache(eq(100L))).thenReturn(role);
// // mock 其它方法
// // 调用 when(roleService.hasAnySuperAdmin(eq(asSet(100L)))).thenReturn(true);
// List<MenuDO> result = permissionService.getRoleMenuListFromCache(roleIds, menuTypes, menusStatuses);
// // 断言 // 调用
// assertSame(menuList, result); boolean has = permissionService.hasAnyPermissions(userId, roles);
// } // 断言
assertTrue(has);
}
@Test
public void testHasAnyPermissions_normal() {
// 准备参数
Long userId = 1L;
String[] roles = new String[]{"system:user:query", "system:user:create"};
// mock 用户与角色的缓存
permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(100L)).build());
RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L)
.setStatus(CommonStatusEnum.ENABLE.getStatus()));
when(roleService.getRoleFromCache(eq(100L))).thenReturn(role);
// mock 其它方法
MenuDO menu = randomPojo(MenuDO.class, o -> o.setId(1000L));
when(menuService.getMenuListByPermissionFromCache(eq("system:user:create"))).thenReturn(singletonList(menu));
permissionService.setMenuRoleCache(ImmutableMultimap.<Long, Long>builder().put(1000L, 100L).build());
// 调用
boolean has = permissionService.hasAnyPermissions(userId, roles);
// 断言
assertTrue(has);
}
@Test
public void testHasAnyRoles_superAdmin() {
// 准备参数
Long userId = 1L;
String[] roles = new String[]{"yunai", "tudou"};
// mock 用户与角色的缓存
permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(100L)).build());
RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L)
.setStatus(CommonStatusEnum.ENABLE.getStatus()));
when(roleService.getRoleFromCache(eq(100L))).thenReturn(role);
// mock 其它方法
when(roleService.hasAnySuperAdmin(eq(asSet(100L)))).thenReturn(true);
// 调用
boolean has = permissionService.hasAnyRoles(userId, roles);
// 断言
assertTrue(has);
}
@Test
public void testHasAnyRoles_normal() {
// 准备参数
Long userId = 1L;
String[] roles = new String[]{"yunai", "tudou"};
// mock 用户与角色的缓存
permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(100L)).build());
RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L).setCode("yunai")
.setStatus(CommonStatusEnum.ENABLE.getStatus()));
when(roleService.getRoleFromCache(eq(100L))).thenReturn(role);
// mock 其它方法
when(roleService.getRolesFromCache(eq(asSet(100L)))).thenReturn(singletonList(role));
// 调用
boolean has = permissionService.hasAnyRoles(userId, roles);
// 断言
assertTrue(has);
}
@Test @Test
public void testGetDeptDataPermission_All() { public void testGetDeptDataPermission_All() {