feature: 实时控制权限
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ spring:
|
||||
active: basic,dev
|
||||
|
||||
# 如果需要无Mysql 无Redis直接启动的话 可以将这两个参数置为true, 并且spring.profile.active: dev换成test
|
||||
# redis的端口可能会被占用,如果被占用请自己修改一下端口号
|
||||
agileboot:
|
||||
embedded:
|
||||
mysql: false
|
||||
|
||||
@@ -5,6 +5,7 @@ import lombok.Data;
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Deprecated
|
||||
@Data
|
||||
public class BaseUser {
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 用户信息
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user