feature: 实时控制权限

This commit is contained in:
valarchie
2023-02-26 22:29:48 +08:00
parent 880c59b4e5
commit 9c105a7630
24 changed files with 280 additions and 95 deletions

View File

@@ -12,6 +12,7 @@ import com.agileboot.domain.system.user.dto.UserDTO;
import com.agileboot.infrastructure.annotations.RateLimit;
import com.agileboot.infrastructure.annotations.RateLimit.CacheType;
import com.agileboot.infrastructure.annotations.RateLimit.LimitType;
import com.agileboot.infrastructure.cache.CacheCenter;
import com.agileboot.infrastructure.cache.map.MapCache;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.CaptchaDTO;
@@ -92,7 +93,8 @@ public class LoginController {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
UserPermissionDTO permissionDTO = new UserPermissionDTO();
permissionDTO.setUser(new UserDTO(loginUser.getEntity()));
permissionDTO.setUser(new UserDTO(CacheCenter.userCache.getObjectById(loginUser.getUserId())));
permissionDTO.setRoleKey(loginUser.getRoleInfo().getRoleKey());
permissionDTO.setPermissions(loginUser.getRoleInfo().getMenuPermissions());
permissionDTO.setDictTypes(MapCache.dictionaryCache());

View File

@@ -15,8 +15,6 @@ import com.agileboot.domain.system.role.query.RoleQuery;
import com.agileboot.domain.system.role.query.UnallocatedRoleQuery;
import com.agileboot.domain.system.user.dto.UserDTO;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
@@ -102,8 +100,7 @@ public class SysRoleController extends BaseController {
@AccessLog(title = "角色管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@Validated @RequestBody UpdateRoleCommand updateCommand) {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
roleApplicationService.updateRole(updateCommand, loginUser);
roleApplicationService.updateRole(updateCommand);
return ResponseDTO.ok();
}

View File

@@ -24,6 +24,7 @@ spring:
active: basic,dev
# 如果需要无Mysql 无Redis直接启动的话 可以将这两个参数置为true, 并且spring.profile.active: dev换成test
# redis的端口可能会被占用如果被占用请自己修改一下端口号
agileboot:
embedded:
mysql: false

View File

@@ -5,6 +5,7 @@ import lombok.Data;
/**
* @author valarchie
*/
@Deprecated
@Data
public class BaseUser {

View File

@@ -15,9 +15,7 @@ import com.agileboot.domain.system.role.query.UnallocatedRoleQuery;
import com.agileboot.domain.system.user.dto.UserDTO;
import com.agileboot.domain.system.user.model.UserModel;
import com.agileboot.domain.system.user.model.UserModelFactory;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.service.TokenService;
import com.agileboot.infrastructure.web.service.UserDetailsServiceImpl;
import com.agileboot.infrastructure.cache.CacheCenter;
import com.agileboot.orm.system.entity.SysRoleEntity;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.orm.system.service.ISysRoleService;
@@ -49,11 +47,6 @@ public class RoleApplicationService {
@NonNull
private ISysUserService userService;
@NonNull
private TokenService tokenService;
@NonNull
private UserDetailsServiceImpl userDetailsService;
public PageDTO<RoleDTO> getRoleList(RoleQuery query) {
Page<SysRoleEntity> page = roleService.page(query.toPage(), query.toQueryWrapper());
@@ -85,12 +78,14 @@ public class RoleApplicationService {
roleModel.checkRoleCanBeDelete();
roleModel.deleteById();
CacheCenter.roleInfoCache.delete(roleModel.getRoleId());
}
}
}
public void updateRole(UpdateRoleCommand updateCommand, LoginUser loginUser) {
public void updateRole(UpdateRoleCommand updateCommand) {
RoleModel roleModel = roleModelFactory.loadById(updateCommand.getRoleId());
roleModel.loadUpdateCommand(updateCommand);
@@ -99,11 +94,7 @@ public class RoleApplicationService {
roleModel.updateById();
if (loginUser.isAdmin()) {
// TODO 如何实时刷新所有改动到的user的权限
loginUser.getRoleInfo().setMenuPermissions(userDetailsService.getMenuPermissions(loginUser.getUserId()));
tokenService.setLoginUser(loginUser);
}
CacheCenter.roleInfoCache.delete(roleModel.getRoleId());
}
public void updateStatus(UpdateStatusCommand command) {
@@ -112,6 +103,8 @@ public class RoleApplicationService {
roleModel.setStatus(command.getStatus());
roleModel.updateById();
CacheCenter.roleInfoCache.delete(roleModel.getRoleId());
}
public void updateDataScope(UpdateDataScopeCommand command) {
@@ -122,6 +115,8 @@ public class RoleApplicationService {
roleModel.generateDeptIdSet();
roleModel.updateById();
CacheCenter.roleInfoCache.delete(roleModel.getRoleId());
}
@@ -147,6 +142,8 @@ public class RoleApplicationService {
updateWrapper.set(SysUserEntity::getRoleId, null).eq(SysUserEntity::getUserId, userId);
userService.update(updateWrapper);
CacheCenter.userCache.delete(userId);
}
}
@@ -162,6 +159,8 @@ public class RoleApplicationService {
UserModel user = userModelFactory.loadById(userId);
user.setRoleId(roleId);
user.updateById();
CacheCenter.userCache.delete(userId);
}
}

View File

@@ -5,7 +5,6 @@ import com.agileboot.common.core.page.PageDTO;
import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.system.post.dto.PostDTO;
import com.agileboot.domain.system.role.dto.RoleDTO;
import com.agileboot.domain.system.role.model.RoleModelFactory;
import com.agileboot.domain.system.user.command.AddUserCommand;
import com.agileboot.domain.system.user.command.ChangeStatusCommand;
import com.agileboot.domain.system.user.command.ResetPasswordCommand;
@@ -59,9 +58,6 @@ public class UserApplicationService {
@NonNull
private TokenService tokenService;
@NonNull
private RoleModelFactory roleModelFactory;
public PageDTO<UserDTO> getUserList(SearchUserQuery<SearchUserDO> query) {
Page<SearchUserDO> userPage = userService.getUserList(query);
@@ -117,6 +113,7 @@ public class UserApplicationService {
model.checkUsernameIsUnique();
model.checkPhoneNumberIsUnique();
model.checkEmailIsUnique();
model.checkFieldRelatedEntityExist();
model.resetPassword(command.getPassword());
model.insert();
@@ -128,6 +125,7 @@ public class UserApplicationService {
model.checkPhoneNumberIsUnique();
model.checkEmailIsUnique();
model.checkFieldRelatedEntityExist();
model.updateById();
CacheCenter.userCache.delete(model.getUserId());
@@ -146,9 +144,6 @@ public class UserApplicationService {
userModel.modifyPassword(command);
userModel.updateById();
loginUser.setEntity(userModel);
tokenService.setLoginUser(loginUser);
CacheCenter.userCache.delete(userModel.getUserId());
}

View File

@@ -6,6 +6,9 @@ import com.agileboot.common.config.AgileBootConfig;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.exception.error.ErrorCode.Business;
import com.agileboot.domain.system.dept.model.DeptModelFactory;
import com.agileboot.domain.system.post.model.PostModelFactory;
import com.agileboot.domain.system.role.model.RoleModelFactory;
import com.agileboot.domain.system.user.command.AddUserCommand;
import com.agileboot.domain.system.user.command.UpdateProfileCommand;
import com.agileboot.domain.system.user.command.UpdateUserCommand;
@@ -27,15 +30,27 @@ public class UserModel extends SysUserEntity {
private ISysUserService userService;
public UserModel(SysUserEntity entity, ISysUserService userService) {
private PostModelFactory postModelFactory;
private DeptModelFactory deptModelFactory;
private RoleModelFactory roleModelFactory;
public UserModel(SysUserEntity entity, ISysUserService userService, PostModelFactory postModelFactory,
DeptModelFactory deptModelFactory, RoleModelFactory roleModelFactory) {
this(userService, postModelFactory, deptModelFactory, roleModelFactory);
if (entity != null) {
BeanUtil.copyProperties(entity, this);
}
this.userService = userService;
}
public UserModel(ISysUserService userService) {
public UserModel(ISysUserService userService, PostModelFactory postModelFactory,
DeptModelFactory deptModelFactory, RoleModelFactory roleModelFactory) {
this.userService = userService;
this.postModelFactory = postModelFactory;
this.deptModelFactory = deptModelFactory;
this.roleModelFactory = roleModelFactory;
}
public void loadAddUserCommand(AddUserCommand command) {
@@ -74,6 +89,23 @@ public class UserModel extends SysUserEntity {
}
}
public void checkFieldRelatedEntityExist() {
if (getPostId() != null) {
postModelFactory.loadById(getPostId());
}
if (getDeptId() != null) {
deptModelFactory.loadById(getDeptId());
}
if (getRoleId() != null) {
roleModelFactory.loadById(getRoleId());
}
}
public void checkEmailIsUnique() {
if (StrUtil.isNotEmpty(getEmail()) && userService.isEmailDuplicated(getEmail(), getUserId())) {
throw new ApiException(ErrorCode.Business.USER_EMAIL_IS_NOT_UNIQUE);

View File

@@ -1,8 +1,10 @@
package com.agileboot.domain.system.user.model;
import cn.hutool.core.bean.BeanUtil;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.domain.system.dept.model.DeptModelFactory;
import com.agileboot.domain.system.post.model.PostModelFactory;
import com.agileboot.domain.system.role.model.RoleModelFactory;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.orm.system.service.ISysUserService;
import lombok.NonNull;
@@ -20,16 +22,25 @@ public class UserModelFactory {
@NonNull
private ISysUserService userService;
@NonNull
private PostModelFactory postModelFactory;
@NonNull
private DeptModelFactory deptModelFactory;
@NonNull
private RoleModelFactory roleModelFactory;
public UserModel loadById(Long userId) {
SysUserEntity byId = userService.getById(userId);
if (byId == null) {
throw new ApiException(ErrorCode.Business.OBJECT_NOT_FOUND, userId, "用户");
}
return new UserModel(byId, userService);
return new UserModel(byId, userService, postModelFactory, deptModelFactory, roleModelFactory);
}
public UserModel create() {
return new UserModel(userService);
return new UserModel(userService, postModelFactory, deptModelFactory, roleModelFactory);
}
}

View File

@@ -7,6 +7,9 @@ import static org.mockito.Mockito.when;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode.Business;
import com.agileboot.domain.system.dept.model.DeptModelFactory;
import com.agileboot.domain.system.post.model.PostModelFactory;
import com.agileboot.domain.system.role.model.RoleModelFactory;
import com.agileboot.domain.system.user.command.UpdateUserPasswordCommand;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
@@ -17,8 +20,12 @@ import org.junit.jupiter.api.Test;
class UserModelTest {
private final ISysUserService userService = mock(ISysUserService.class);
private final PostModelFactory postModelFactory = mock(PostModelFactory.class);
private final DeptModelFactory deptModelFactory = mock(DeptModelFactory.class);
private final RoleModelFactory roleModelFactory = mock(RoleModelFactory.class);
private final UserModelFactory userModelFactory = new UserModelFactory(userService);
private final UserModelFactory userModelFactory = new UserModelFactory(userService, postModelFactory,
deptModelFactory, roleModelFactory);
private static final long USER_ID = 1L;
private static final long ADMIN_USER_ID = 1L;

View File

@@ -6,6 +6,7 @@ import com.agileboot.infrastructure.cache.guava.GuavaCacheService;
import com.agileboot.infrastructure.cache.redis.RedisCacheService;
import com.agileboot.infrastructure.cache.redis.RedisCacheTemplate;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.orm.system.entity.SysDeptEntity;
import com.agileboot.orm.system.entity.SysUserEntity;
import javax.annotation.PostConstruct;
@@ -28,6 +29,8 @@ public class CacheCenter {
public static RedisCacheTemplate<SysUserEntity> userCache;
public static RedisCacheTemplate<RoleInfo> roleInfoCache;
@PostConstruct
public void init() {
GuavaCacheService guavaCache = SpringUtil.getBean(GuavaCacheService.class);
@@ -39,6 +42,7 @@ public class CacheCenter {
captchaCache = redisCache.captchaCache;
loginUserCache = redisCache.loginUserCache;
userCache = redisCache.userCache;
roleInfoCache = redisCache.roleInfoCache;
}
}

View File

@@ -14,6 +14,7 @@ public enum CacheKeyEnum {
LOGIN_USER_KEY("login_tokens:", 30, TimeUnit.MINUTES),
RATE_LIMIT_KEY("rate_limit:", 60, TimeUnit.SECONDS),
USER_ENTITY_KEY("user_entity:", 60, TimeUnit.MINUTES),
ROLE_INFO_KEY("role_info:", 60, TimeUnit.MINUTES),
;

View File

@@ -3,6 +3,8 @@ package com.agileboot.infrastructure.cache.redis;
import cn.hutool.extra.spring.SpringUtil;
import com.agileboot.infrastructure.cache.RedisUtil;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.infrastructure.web.service.UserDetailsServiceImpl;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.orm.system.service.ISysUserService;
import java.io.Serializable;
@@ -24,6 +26,7 @@ public class RedisCacheService {
public RedisCacheTemplate<String> captchaCache;
public RedisCacheTemplate<LoginUser> loginUserCache;
public RedisCacheTemplate<SysUserEntity> userCache;
public RedisCacheTemplate<RoleInfo> roleInfoCache;
@PostConstruct
public void init() {
@@ -40,6 +43,15 @@ public class RedisCacheService {
}
};
roleInfoCache = new RedisCacheTemplate<RoleInfo>(redisUtil, CacheKeyEnum.ROLE_INFO_KEY) {
@Override
public RoleInfo getObjectFromDb(Object id) {
UserDetailsServiceImpl userDetailsService = SpringUtil.getBean(UserDetailsServiceImpl.class);
return userDetailsService.getRoleInfo((Long) id);
}
};
}

View File

@@ -54,7 +54,7 @@ public class RedisCacheTemplate<T> {
String cachedKey = generateKey(id);
try {
Optional<T> optional = guavaCache.get(cachedKey);
log.debug("find the guava cache of key: {}", cachedKey);
// log.debug("find the guava cache of key: {}", cachedKey);
if (!optional.isPresent()) {
T objectFromDb = getObjectFromDb(id);

View File

@@ -1,7 +1,6 @@
package com.agileboot.infrastructure.web.domain.login;
import com.agileboot.common.core.base.BaseUser;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.infrastructure.cache.CacheCenter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Collection;
import lombok.Data;
@@ -15,9 +14,11 @@ import org.springframework.security.core.userdetails.UserDetails;
*/
@Data
@NoArgsConstructor
public class LoginUser extends BaseUser implements UserDetails {
public class LoginUser implements UserDetails {
private static final long serialVersionUID = 1L;
private Long userId;
/**
* 用户唯一标识
*/
@@ -38,29 +39,37 @@ public class LoginUser extends BaseUser implements UserDetails {
*/
private LoginInfo loginInfo = new LoginInfo();
/**
* 角色信息
*/
private RoleInfo roleInfo = new RoleInfo();
private SysUserEntity entity;
public LoginUser(SysUserEntity entity, RoleInfo roleInfo) {
setUsername(entity.getUsername());
setUserId(entity.getUserId());
setDeptId(entity.getDeptId());
setRoleId(entity.getRoleId());
if (roleInfo != null) {
this.roleInfo = roleInfo;
}
this.entity = entity;
public LoginUser(Long userId) {
this.userId = userId;
}
public RoleInfo getRoleInfo() {
return CacheCenter.roleInfoCache.getObjectById(getRoleId());
}
public Long getRoleId() {
if (isAdmin()) {
return RoleInfo.ADMIN_ROLE_ID;
} else {
return CacheCenter.userCache.getObjectById(userId).getRoleId();
}
}
public Long getDeptId() {
return CacheCenter.userCache.getObjectById(userId).getDeptId();
}
@Override
public String getUsername() {
return CacheCenter.userCache.getObjectById(userId).getUsername();
}
@JsonIgnore
@Override
public String getPassword() {
return entity.getPassword();
return CacheCenter.userCache.getObjectById(userId).getPassword();
}

View File

@@ -20,6 +20,26 @@ import org.apache.commons.collections4.SetUtils;
@NoArgsConstructor
public class RoleInfo {
public static final RoleInfo EMPTY_ROLE = new RoleInfo();
public static final long ADMIN_ROLE_ID = -1;
public static final String ADMIN_ROLE_KEY = "admin";
public static final String ALL_PERMISSIONS = "*:*:*";
public static final Set<String> ADMIN_PERMISSIONS = SetUtils.hashSet(ALL_PERMISSIONS);
public RoleInfo(Long roleId, String roleKey, DataScopeEnum dataScope, Set<Long> deptIdSet,
Set<String> menuPermissions, Set<Long> menuIds) {
this.roleId = roleId;
this.roleKey = roleKey;
this.dataScope = dataScope;
this.deptIdSet = deptIdSet;
this.menuPermissions = menuPermissions != null ? menuPermissions : SetUtils.emptySet();
this.menuIds = menuIds != null ? menuIds : SetUtils.emptySet();
}
@Deprecated
public RoleInfo(SysRoleEntity entity, String roleKey, Set<String> menuPermissions, Set<Long> menuIds) {
if (entity != null) {
this.roleId = entity.getRoleId();
@@ -34,7 +54,6 @@ public class RoleInfo {
this.roleKey = roleKey;
this.menuPermissions = menuPermissions != null ? menuPermissions : SetUtils.emptySet();
this.menuIds = menuIds != null ? menuIds : SetUtils.emptySet();
}
}

View File

@@ -98,7 +98,8 @@ public class LoginService {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginDTO.getUsername(), LoginStatusEnum.LOGIN_SUCCESS,
LoginStatusEnum.LOGIN_SUCCESS.description()));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getEntity());
SysUserEntity userEntity = CacheCenter.userCache.getObjectById(loginUser.getUserId());
recordLoginInfo(userEntity);
// 生成token
return tokenService.createToken(loginUser);
}

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import java.util.Set;
import org.springframework.stereotype.Service;
@@ -14,11 +15,6 @@ import org.springframework.stereotype.Service;
@Service("permission")
public class MenuPermissionService {
/**
* 所有权限标识
*/
private static final String ALL_PERMISSION = "*:*:*";
/**
* 验证用户是否具备某权限
@@ -46,7 +42,7 @@ public class MenuPermissionService {
* @return 用户是否具备某权限
*/
private boolean has(Set<String> permissions, String permission) {
return permissions.contains(ALL_PERMISSION) || permissions.contains(StrUtil.trim(permission));
return permissions.contains(RoleInfo.ALL_PERMISSIONS) || permissions.contains(StrUtil.trim(permission));
}
}

View File

@@ -1,16 +1,21 @@
package com.agileboot.infrastructure.web.service;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.orm.common.enums.DataScopeEnum;
import com.agileboot.orm.common.enums.UserStatusEnum;
import com.agileboot.orm.common.util.BasicEnumUtil;
import com.agileboot.orm.system.entity.SysMenuEntity;
import com.agileboot.orm.system.entity.SysRoleEntity;
import com.agileboot.orm.system.entity.SysRoleMenuEntity;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.orm.system.service.ISysMenuService;
import com.agileboot.orm.system.service.ISysRoleMenuService;
import com.agileboot.orm.system.service.ISysRoleService;
import com.agileboot.orm.system.service.ISysUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -22,6 +27,7 @@ import java.util.stream.Collectors;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.SetUtils;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -48,6 +54,9 @@ public class UserDetailsServiceImpl implements UserDetailsService {
@NonNull
private ISysMenuService menuService;
@NonNull
private ISysRoleService roleService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -61,17 +70,49 @@ public class UserDetailsServiceImpl implements UserDetailsService {
throw new ApiException(ErrorCode.Business.USER_IS_DISABLE, username);
}
SysRoleEntity roleEntity = userService.getRoleOfUser(userEntity.getUserId());
RoleInfo roleInfo = new RoleInfo(
roleEntity,
getRoleKey(userEntity.getUserId()),
getMenuPermissions(userEntity.getUserId()),
getMenuIds(userEntity.getUserId(), userEntity.getRoleId())
);
return new LoginUser(userEntity, roleInfo);
return new LoginUser(userEntity.getUserId());
}
public RoleInfo getRoleInfo(Long roleId) {
if (roleId == null) {
return RoleInfo.EMPTY_ROLE;
}
if (roleId == RoleInfo.ADMIN_ROLE_ID) {
LambdaQueryWrapper<SysMenuEntity> menuQuery = Wrappers.lambdaQuery();
menuQuery.select(SysMenuEntity::getMenuId);
List<SysMenuEntity> allMenus = menuService.list(menuQuery);
Set<Long> allMenuIds = allMenus.stream().map(SysMenuEntity::getMenuId).collect(Collectors.toSet());
return new RoleInfo(RoleInfo.ADMIN_ROLE_ID, RoleInfo.ADMIN_ROLE_KEY, DataScopeEnum.ALL, SetUtils.emptySet(),
RoleInfo.ADMIN_PERMISSIONS, allMenuIds);
}
SysRoleEntity roleEntity = roleService.getById(roleId);
if (roleEntity == null) {
return RoleInfo.EMPTY_ROLE;
}
List<SysMenuEntity> menuList = roleService.getMenuListByRoleId(roleId);
Set<Long> menuIds = menuList.stream().map(SysMenuEntity::getMenuId).collect(Collectors.toSet());
Set<String> permissions = menuList.stream().map(SysMenuEntity::getPerms).collect(Collectors.toSet());
DataScopeEnum dataScopeEnum = BasicEnumUtil.fromValue(DataScopeEnum.class, roleEntity.getDataScope());
Set<Long> deptIdSet = SetUtils.emptySet();
if (StrUtil.isNotEmpty(roleEntity.getDeptIdSet())) {
deptIdSet = StrUtil.split(roleEntity.getDeptIdSet(), ",").stream()
.map(Convert::toLong).collect(Collectors.toSet());
}
return new RoleInfo(roleId, roleEntity.getRoleKey(), dataScopeEnum, deptIdSet, permissions, menuIds);
}
/**
* 获取角色数据权限
* @param userId 用户信息

View File

@@ -1,25 +1,34 @@
package com.agileboot.infrastructure.web.domain.permission.checker;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import org.apache.commons.collections4.SetUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class CustomDataPermissionCheckerTest {
private final ISysDeptService deptService = mock(ISysDeptService.class);
public LoginUser loginUser = mock(LoginUser.class);
@BeforeEach
public void mockBefore() {
when(loginUser.getRoleInfo()).thenReturn(RoleInfo.EMPTY_ROLE);
}
@Test
void testCheckWhenParameterNull() {
CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService);
boolean check1 = customChecker.check(null, null);
boolean check2 = customChecker.check(new LoginUser(), null);
boolean check2 = customChecker.check(loginUser, null);
boolean check3 = customChecker.check(null, new DataCondition());
assertFalse(check1);
@@ -31,7 +40,7 @@ class CustomDataPermissionCheckerTest {
void testCheckWhenTargetDeptIdNull() {
CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService);
boolean check = customChecker.check(new LoginUser(), new DataCondition(null, 1L));
boolean check = customChecker.check(loginUser, new DataCondition(null, 1L));
assertFalse(check);
}
@@ -41,7 +50,8 @@ class CustomDataPermissionCheckerTest {
void testCheckWhenRoleIsNull() {
CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService);
boolean check = customChecker.check(new LoginUser(), new DataCondition(1L, 1L));
when(loginUser.getRoleInfo()).thenReturn(null);
boolean check = customChecker.check(loginUser, new DataCondition(1L, 1L));
assertFalse(check);
}
@@ -51,10 +61,8 @@ class CustomDataPermissionCheckerTest {
void testCheckWhenNotContainTargetDeptId() {
CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService);
LoginUser loginUser = new LoginUser();
loginUser.setRoleInfo(new RoleInfo());
loginUser.getRoleInfo().setDeptIdSet(SetUtils.hashSet(2L));
boolean check = customChecker.check(new LoginUser(), new DataCondition(1L, 1L));
boolean check = customChecker.check(loginUser, new DataCondition(1L, 1L));
assertFalse(check);
}
@@ -63,13 +71,11 @@ class CustomDataPermissionCheckerTest {
@Test
void testCheckWhenContainTargetDeptId() {
CustomDataPermissionChecker customChecker = new CustomDataPermissionChecker(deptService);
LoginUser loginUser = new LoginUser();
loginUser.setRoleInfo(new RoleInfo());
loginUser.getRoleInfo().setDeptIdSet(SetUtils.hashSet(1L));
boolean check = customChecker.check(loginUser, new DataCondition(1L, 1L));
boolean check = customChecker.check(new LoginUser(), new DataCondition(1L, 1L));
assertFalse(check);
assertTrue(check);
}

View File

@@ -4,10 +4,13 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -15,6 +18,13 @@ class DeptTreeDataPermissionCheckerTest {
private final ISysDeptService deptService = mock(ISysDeptService.class);
public LoginUser loginUser = mock(LoginUser.class);
@BeforeEach
public void mockBefore() {
when(loginUser.getRoleInfo()).thenReturn(RoleInfo.EMPTY_ROLE);
}
@Test
void testCheckWhenParameterNull() {
DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService);
@@ -22,7 +32,7 @@ class DeptTreeDataPermissionCheckerTest {
boolean check1 = checker.check(null, null);
boolean check2 = checker.check(new LoginUser(), null);
boolean check3 = checker.check(null, new DataCondition());
boolean check4 = checker.check(new LoginUser(), new DataCondition());
boolean check4 = checker.check(loginUser, new DataCondition());
assertFalse(check1);
assertFalse(check2);
@@ -35,9 +45,9 @@ class DeptTreeDataPermissionCheckerTest {
void testCheckWhenIsChildOfDept() {
DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService);
Mockito.when(deptService.isChildOfTheDept(any(), any())).thenReturn(true);
LoginUser loginUser = new LoginUser();
loginUser.setDeptId(1L);
when(deptService.isChildOfTheDept(any(), any())).thenReturn(true);
when(loginUser.getDeptId()).thenReturn(1L);
DataCondition dataCondition = new DataCondition();
dataCondition.setTargetDeptId(2L);
@@ -52,8 +62,7 @@ class DeptTreeDataPermissionCheckerTest {
DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService);
Mockito.when(deptService.isChildOfTheDept(any(), any())).thenReturn(false);
LoginUser loginUser = new LoginUser();
loginUser.setDeptId(1L);
when(loginUser.getDeptId()).thenReturn(1L);
DataCondition dataCondition = new DataCondition();
dataCondition.setTargetDeptId(1L);
@@ -68,8 +77,7 @@ class DeptTreeDataPermissionCheckerTest {
DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService);
Mockito.when(deptService.isChildOfTheDept(any(), any())).thenReturn(false);
LoginUser loginUser = new LoginUser();
loginUser.setDeptId(1L);
when(loginUser.getDeptId()).thenReturn(1L);
DataCondition dataCondition = new DataCondition();
dataCondition.setTargetDeptId(2L);

View File

@@ -3,16 +3,27 @@ package com.agileboot.infrastructure.web.domain.permission.checker;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class SingleDeptDataPermissionCheckerTest {
private final ISysDeptService deptService = mock(ISysDeptService.class);
public LoginUser loginUser = mock(LoginUser.class);
@BeforeEach
public void mockBefore() {
when(loginUser.getRoleInfo()).thenReturn(RoleInfo.EMPTY_ROLE);
}
@Test
void testCheckWhenParameterNull() {
SingleDeptDataPermissionChecker checker = new SingleDeptDataPermissionChecker(deptService);
@@ -20,7 +31,7 @@ class SingleDeptDataPermissionCheckerTest {
boolean check1 = checker.check(null, null);
boolean check2 = checker.check(new LoginUser(), null);
boolean check3 = checker.check(null, new DataCondition());
boolean check4 = checker.check(new LoginUser(), new DataCondition());
boolean check4 = checker.check(loginUser, new DataCondition());
assertFalse(check1);
assertFalse(check2);
@@ -31,8 +42,7 @@ class SingleDeptDataPermissionCheckerTest {
@Test
void testCheckWhenSameDeptId() {
SingleDeptDataPermissionChecker checker = new SingleDeptDataPermissionChecker(deptService);
LoginUser loginUser = new LoginUser();
loginUser.setDeptId(1L);
when(loginUser.getDeptId()).thenReturn(1L);
DataCondition dataCondition = new DataCondition();
dataCondition.setTargetDeptId(1L);
@@ -45,8 +55,7 @@ class SingleDeptDataPermissionCheckerTest {
@Test
void testCheckWhenDifferentDeptId() {
SingleDeptDataPermissionChecker checker = new SingleDeptDataPermissionChecker(deptService);
LoginUser loginUser = new LoginUser();
loginUser.setDeptId(1L);
when(loginUser.getDeptId()).thenReturn(1L);
DataCondition dataCondition = new DataCondition();
dataCondition.setTargetUserId(2L);

View File

@@ -1,7 +1,10 @@
package com.agileboot.orm.system.mapper;
import com.agileboot.orm.system.entity.SysMenuEntity;
import com.agileboot.orm.system.entity.SysRoleEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import org.apache.ibatis.annotations.Select;
/**
* <p>
@@ -13,4 +16,19 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface SysRoleMapper extends BaseMapper<SysRoleEntity> {
/**
* 根据角色ID查询对应的菜单权限
*
* @param roleId 角色ID
* @return 权限列表
*/
@Select("SELECT m.* "
+ "FROM sys_menu m "
+ " LEFT JOIN sys_role_menu rm ON m.menu_id = rm.menu_id "
+ " LEFT JOIN sys_role r ON r.role_id = rm.role_id "
+ "WHERE m.status = 1 AND m.deleted = 0 "
+ " AND r.status = 1 AND r.deleted = 0 "
+ " AND r.role_id = #{roleId}")
List<SysMenuEntity> getMenuListByRoleId(Long roleId);
}

View File

@@ -1,7 +1,9 @@
package com.agileboot.orm.system.service;
import com.agileboot.orm.system.entity.SysMenuEntity;
import com.agileboot.orm.system.entity.SysRoleEntity;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
@@ -38,5 +40,12 @@ public interface ISysRoleService extends IService<SysRoleEntity> {
*/
boolean isAssignedToUsers(Long roleId);
/**
* 获取用户的权限列表
* @param roleId
* @return
*/
List<SysMenuEntity> getMenuListByRoleId(Long roleId);
}

View File

@@ -1,5 +1,6 @@
package com.agileboot.orm.system.service.impl;
import com.agileboot.orm.system.entity.SysMenuEntity;
import com.agileboot.orm.system.entity.SysRoleEntity;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.orm.system.mapper.SysRoleMapper;
@@ -7,6 +8,7 @@ import com.agileboot.orm.system.mapper.SysUserMapper;
import com.agileboot.orm.system.service.ISysRoleService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.util.List;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -49,5 +51,10 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRoleEntity
return userMapper.exists(queryWrapper);
}
@Override
public List<SysMenuEntity> getMenuListByRoleId(Long roleId) {
return baseMapper.getMenuListByRoleId(roleId);
}
}