perf: 优化租户组织机构数据权限相关问题

pull/9/head
Carina 3 years ago
parent 7368a0cf39
commit 0812c9f143

@ -59,6 +59,7 @@ public interface MenuApi {
/** /**
* *
*
* @param parentId ID * @param parentId ID
* @return ResultVo * @return ResultVo
*/ */
@ -84,10 +85,12 @@ public interface MenuApi {
/** /**
* - * -
*
* @param label
* @return ResultVo * @return ResultVo
*/ */
@GetMapping("/getMenuAndPermsTree") @GetMapping("/getMenuAndPermsTree")
ResultVo<?> getMenuAndPermsTree(); ResultVo<?> getMenuAndPermsTree(String label);
/** /**
* *

@ -103,4 +103,10 @@ public class MenuModel extends ApiWrapper {
@Validator({ValidatorType.IS_NOT_NULL}) @Validator({ValidatorType.IS_NOT_NULL})
private String alwaysShow; private String alwaysShow;
/** 标签 */
@ApiModelProperty(value = "标签")
@ExcelIgnore
@Validator({ValidatorType.IS_NOT_NULL})
private String label;
} }

@ -60,10 +60,18 @@ public class RoleModel extends ApiWrapper {
@ValidatorLenMax(1) @ValidatorLenMax(1)
private String izLock; private String izLock;
/** 标签 */
@ApiModelProperty(value = "标签")
@ExcelProperty(value = "标签", order = 4)
@ExcelInfo(dictType = "menu_role_type")
@Validator({ValidatorType.IS_NOT_NULL})
@ValidatorLenMax(1)
private String label;
/** 授权数据范围 */ /** 授权数据范围 */
@ApiModelProperty(value = "授权数据范围") @ApiModelProperty(value = "授权数据范围")
@ExcelProperty(value = "授权数据范围", order = 4) @ExcelProperty(value = "授权数据范围", order = 5)
@ExcelInfo(dictType = "role_data_scope") @ExcelInfo(dictType = "role_data_scope")
@Validator({ValidatorType.IS_NOT_NULL}) @Validator({ValidatorType.IS_NOT_NULL})
@ValidatorLenMax(5) @ValidatorLenMax(5)
@ -71,7 +79,7 @@ public class RoleModel extends ApiWrapper {
/** 备注 */ /** 备注 */
@ApiModelProperty(value = "备注") @ApiModelProperty(value = "备注")
@ExcelProperty(value = "备注", order = 5) @ExcelProperty(value = "备注", order = 6)
@ExcelInfo @ExcelInfo
@ValidatorLenMax(255) @ValidatorLenMax(255)
private String remark; private String remark;

@ -99,4 +99,8 @@ public class UserInfo extends ApiWrapper {
@ApiModelProperty(value = "密码强度") @ApiModelProperty(value = "密码强度")
private String passwordLevel; private String passwordLevel;
/** 多租户字段 */
@ApiModelProperty(value = "多租户ID")
private String tenantId;
} }

@ -148,7 +148,20 @@ public class UserModel extends ApiWrapper {
@ValidatorLenMax(1) @ValidatorLenMax(1)
private String izExistOrg; private String izExistOrg;
/** 允许切换租户0 不允许 1 允许) */
@ApiModelProperty(value = "是否允许切换运营商")
@ExcelIgnore
private String enableSwitchTenant;
/** 切换后的租户id*/
@JsonIgnore
@ExcelIgnore
private String switchTenantId;
/** 切换后的租户管理员*/
@JsonIgnore
@ExcelIgnore
private String switchTenantUserId;
} }

@ -28,6 +28,10 @@ public enum DictType {
NO_YES_NO("no_yes","0", "否"), NO_YES_NO("no_yes","0", "否"),
NO_YES_YES("no_yes","1", "是"), NO_YES_YES("no_yes","1", "是"),
/** 菜单 标签 */
MENU_LABEL_SYSTEM("menu_role_type","0", "系统模块"),
MENU_LABEL_FUNCTION("menu_role_type","1", "功能模块"),
/** 菜单 */ /** 菜单 */
MENU_MENU("menu_type","1", "菜单"), MENU_MENU("menu_type","1", "菜单"),
MENU_BUTTON("menu_type","2", "按钮"), MENU_BUTTON("menu_type","2", "按钮"),

@ -107,8 +107,13 @@ public class QueryDataPermsHandler implements QueryBuilderChain{
// 1. 当前用户 // 1. 当前用户
UserModel currUser = UserUtil.getUser(); UserModel currUser = UserUtil.getUser();
String userId = StringUtils.isNotEmpty(currUser.getSwitchTenantUserId())
? currUser.getSwitchTenantUserId()
: currUser.getId();
// 2. 当前用户 组织机构集合 // 2. 当前用户 组织机构集合
List<UserOrgRefModel> userOrgRefModelList = UserUtil.getOrgListByUserId(currUser.getId()); List<UserOrgRefModel> userOrgRefModelList = UserUtil.getOrgListByUserId(userId);
List<String> orgIdGroupList = Lists.newArrayListWithCapacity(userOrgRefModelList.size()); List<String> orgIdGroupList = Lists.newArrayListWithCapacity(userOrgRefModelList.size());
for (UserOrgRefModel userOrgRefModel : userOrgRefModelList) { for (UserOrgRefModel userOrgRefModel : userOrgRefModelList) {
orgIdGroupList.add(userOrgRefModel.getOrgIds()); orgIdGroupList.add(userOrgRefModel.getOrgIds());
@ -123,7 +128,7 @@ public class QueryDataPermsHandler implements QueryBuilderChain{
conditionType = ConditionType.ALL; conditionType = ConditionType.ALL;
}else{ }else{
// 如果不是超级管理员 则获得当前用户的默认角色下的 授权数据权限类型 // 如果不是超级管理员 则获得当前用户的默认角色下的 授权数据权限类型
RoleModel defRole = UserUtil.getUserDefRoleByUserId(currUser.getId()); RoleModel defRole = UserUtil.getUserDefRoleByUserId(userId);
if(null != defRole){ if(null != defRole){
conditionType = ConditionType.getConditionType(defRole.getDataScope()); conditionType = ConditionType.getConditionType(defRole.getDataScope());
} }
@ -164,7 +169,7 @@ public class QueryDataPermsHandler implements QueryBuilderChain{
}); });
}else { }else {
// 查自身 // 查自身
wra.eq(FieldUtil.humpToUnderline(MyBatisConstants.FIELD_CREATE_BY), currUser.getId()); wra.eq(FieldUtil.humpToUnderline(MyBatisConstants.FIELD_CREATE_BY), userId);
} }
}); });
} }

@ -59,14 +59,14 @@ public class QueryTenantHandler implements QueryBuilderChain{
// 自身责任 -- 判断多租户 // 自身责任 -- 判断多租户
boolean tenantFlag = ReflectUtil.hasField(entityClazz, MyBatisConstants.FIELD_TENANT); boolean tenantFlag = ReflectUtil.hasField(entityClazz, MyBatisConstants.FIELD_TENANT);
if(tenantFlag) { if(tenantFlag) {
String tenantId = UserUtil.getTenantId(); UserModel currUser = UserUtil.getUser();
//UserModel user = UserUtil.getUser();
// 超级管理员可以操作 无租户限制, 其余用户全部有租户限制 // 切换运营商后 组织ID 不同
// if(!UserUtil.SUPER_ADMIN.equals(user.getUsername()) && String tenantId = StringUtils.isNotEmpty(currUser.getSwitchTenantId())
// StringUtils.isNotEmpty(tenantId) ? currUser.getSwitchTenantId()
// ){ : currUser.getTenantId();
wrapper.eq(FieldUtil.humpToUnderline(MyBatisConstants.FIELD_TENANT), tenantId);
//} wrapper.eq(FieldUtil.humpToUnderline(MyBatisConstants.FIELD_TENANT), tenantId);
} }
return wrapper; return wrapper;
} }
@ -81,19 +81,18 @@ public class QueryTenantHandler implements QueryBuilderChain{
// 自身责任 -- 判断多租户 // 自身责任 -- 判断多租户
boolean tenantFlag = ReflectUtil.hasField(entityClazz, MyBatisConstants.FIELD_TENANT); boolean tenantFlag = ReflectUtil.hasField(entityClazz, MyBatisConstants.FIELD_TENANT);
if(tenantFlag) { if(tenantFlag) {
String tenantId = UserUtil.getTenantId(); UserModel currUser = UserUtil.getUser();
//UserModel user = UserUtil.getUser();
// 超级管理员可以操作 无租户限制, 其余用户全部有租户限制 // 切换运营商后 组织ID 不同
// if(!UserUtil.SUPER_ADMIN.equals(user.getUsername()) && String tenantId = StringUtils.isNotEmpty(currUser.getSwitchTenantId())
// StringUtils.isNotEmpty(tenantId) ? currUser.getSwitchTenantId()
// ){ : currUser.getTenantId();
String fieldName = webQueryConf.get(MyBatisConstants.FIELD_TENANT); String fieldName = webQueryConf.get(MyBatisConstants.FIELD_TENANT);
if(StringUtils.isEmpty(fieldName)){ if(StringUtils.isEmpty(fieldName)){
fieldName = FieldUtil.humpToUnderline(MyBatisConstants.FIELD_TENANT); fieldName = FieldUtil.humpToUnderline(MyBatisConstants.FIELD_TENANT);
} }
wrapper.eq(fieldName, tenantId); wrapper.eq(fieldName, tenantId);
//}
} }
return wrapper; return wrapper;
} }

@ -44,6 +44,9 @@ public class TenantUtil {
/** 前缀 */ /** 前缀 */
public static final String PREFIX_CODE = "tenant:id:"; public static final String PREFIX_CODE = "tenant:id:";
/** 超级管理员 租户ID */
public static final String SUPER_ADMIN_TENANT_ID = "0";
/** 租户 Api */ /** 租户 Api */
private static TenantApi tenantApi; private static TenantApi tenantApi;

@ -659,6 +659,51 @@ public class UserUtil {
// ============== 刷新缓存 ============== // ============== 刷新缓存 ==============
/**
*
* @return UserModel
*/
public static boolean updateUser(UserModel user){
if(null == user){
return false;
}
// 先清空缓存
boolean flag = refreshUser(user);
if(!flag){
return false;
}
// 缓存Key
String cacheKey = PREFIX_ID + user.getId();
try {
// 存入缓存
CacheUtil.put(cacheKey, user);
}catch (Exception e){
log.error(e.getMessage(), e);
}
try {
// 分布式加锁
if(!DistributedLockUtil.lock(cacheKey)){
// 无法申领分布式锁
log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage());
return false;
}
// 存入缓存
flag = CacheUtil.put(cacheKey, user);
}catch (Exception e){
flag = false;
log.error(e.getMessage(), e);
}finally {
// 释放锁
DistributedLockUtil.unlock(cacheKey);
}
return flag;
}
/** /**
* - * -
* @param user * @param user
@ -984,7 +1029,7 @@ public class UserUtil {
// 如果是超级管理员 则不进行租户处理 默认为0 // 如果是超级管理员 则不进行租户处理 默认为0
if(StringUtils.equals(SUPER_ADMIN, user.getUsername())){ if(StringUtils.equals(SUPER_ADMIN, user.getUsername())){
return "0"; return TenantUtil.SUPER_ADMIN_TENANT_ID;
} }
return user.getTenantId(); return user.getTenantId();
} }

@ -49,6 +49,7 @@ public enum SystemMsg implements BaseMsg {
EXCEPTION_ROLE_UNIQUE(20200,"角色编号或名称重复,该角色已存在!"), EXCEPTION_ROLE_UNIQUE(20200,"角色编号或名称重复,该角色已存在!"),
EXCEPTION_ROLE_ID_NOT_NULL(20201,"角色Id不可为空"), EXCEPTION_ROLE_ID_NOT_NULL(20201,"角色Id不可为空"),
EXCEPTION_ROLE_PERMS_ERROR(20202,"角色权限设置失败"), EXCEPTION_ROLE_PERMS_ERROR(20202,"角色权限设置失败"),
EXCEPTION_ROLE_USED(20203,"角色删除失败, 被删除角色正在被其他用户使用"),
@ -68,7 +69,8 @@ public enum SystemMsg implements BaseMsg {
EXCEPTION_USER_ILLEGAL_PARAMETER(20311,"非法参数"), EXCEPTION_USER_ILLEGAL_PARAMETER(20311,"非法参数"),
EXCEPTION_USER_HANDLE_SELF(20312,"不可操作自身"), EXCEPTION_USER_HANDLE_SELF(20312,"不可操作自身"),
EXCEPTION_USER_HANDLE_SUPER_ADMIN(20313,"不可操作超管账号"), EXCEPTION_USER_HANDLE_SUPER_ADMIN(20313,"不可操作超管账号"),
EXCEPTION_USER_SWITCH_TENANT_NOT_HAS_ADMIN(20314,"此租户不存在管理员,不能切换"),
EXCEPTION_USER_SWITCH_NOT_ALLOWED(20315,"不允许切换租户"),
/** /**
* *

@ -70,6 +70,9 @@ public class SysMenu extends BaseEntity {
/** 是否总是显示 0为否 1为是 */ /** 是否总是显示 0为否 1为是 */
private String alwaysShow; private String alwaysShow;
/** 标签 */
private String label;
// ======================================== // ========================================
/** 逻辑删除字段 */ /** 逻辑删除字段 */

@ -101,11 +101,11 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
*/ */
@ApiOperation(value = "根据 获得用户 菜单 - 权限", notes = "根据 获得用户 菜单 - 权限") @ApiOperation(value = "根据 获得用户 菜单 - 权限", notes = "根据 获得用户 菜单 - 权限")
@Override @Override
public ResultVo<?> getMenuAndPermsTree() { public ResultVo<?> getMenuAndPermsTree(String label) {
UserModel user = UserUtil.getUser(); UserModel user = UserUtil.getUser();
// 获得当前用户菜单 // 获得当前用户菜单
List<MenuModel> menuModelList = iUserRoleRefService.getMenuAllListByUserId(user.getId()); List<MenuModel> menuModelList = iUserRoleRefService.getMenuAllListByUserId(user.getId(), label);
// 这里有坑 如果 为 菜单数据 且 组件(Component)地址为空 不会跳转到主页 也不报错 // 这里有坑 如果 为 菜单数据 且 组件(Component)地址为空 不会跳转到主页 也不报错
// 修复菜单问题导致无法跳转主页 // 修复菜单问题导致无法跳转主页
@ -200,6 +200,9 @@ public class MenuRestController extends BaseRestController<SysMenu, MenuModel, I
/** /**
* *
*
* @param label
* @param parentId ID
* @return ResultVo * @return ResultVo
*/ */
@ApiOperation(value = "获得列表菜单树 懒加载", notes = "获得列表菜单树 懒加载") @ApiOperation(value = "获得列表菜单树 懒加载", notes = "获得列表菜单树 懒加载")

@ -23,20 +23,24 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.opsli.api.wrapper.system.org.SysOrgModel; import org.opsli.api.wrapper.system.org.SysOrgModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.constants.MyBatisConstants; import org.opsli.common.constants.MyBatisConstants;
import org.opsli.common.enums.DictType; import org.opsli.common.enums.DictType;
import org.opsli.common.exception.ServiceException; import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.FieldUtil; import org.opsli.common.utils.FieldUtil;
import org.opsli.core.base.entity.HasChildren; import org.opsli.core.base.entity.HasChildren;
import org.opsli.core.base.service.impl.CrudServiceImpl; import org.opsli.core.base.service.impl.CrudServiceImpl;
import org.opsli.core.msg.CoreMsg;
import org.opsli.core.persistence.querybuilder.GenQueryBuilder; import org.opsli.core.persistence.querybuilder.GenQueryBuilder;
import org.opsli.core.persistence.querybuilder.QueryBuilder; import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.persistence.querybuilder.chain.QueryTenantHandler; import org.opsli.core.persistence.querybuilder.chain.QueryTenantHandler;
import org.opsli.core.utils.TenantUtil;
import org.opsli.core.utils.UserUtil; import org.opsli.core.utils.UserUtil;
import org.opsli.modulars.system.SystemMsg; import org.opsli.modulars.system.SystemMsg;
import org.opsli.modulars.system.org.entity.SysOrg; import org.opsli.modulars.system.org.entity.SysOrg;
import org.opsli.modulars.system.org.mapper.SysOrgMapper; import org.opsli.modulars.system.org.mapper.SysOrgMapper;
import org.opsli.modulars.system.org.service.ISysOrgService; import org.opsli.modulars.system.org.service.ISysOrgService;
import org.opsli.modulars.system.user.service.IUserRoleRefService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -63,6 +67,8 @@ public class SysOrgServiceImpl extends CrudServiceImpl<SysOrgMapper, SysOrg, Sys
@Autowired(required = false) @Autowired(required = false)
private SysOrgMapper mapper; private SysOrgMapper mapper;
@Autowired
private IUserRoleRefService iUserRoleRefService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -102,10 +108,20 @@ public class SysOrgServiceImpl extends CrudServiceImpl<SysOrgMapper, SysOrg, Sys
sysOrgModel.getId()); sysOrgModel.getId());
} }
// 刷新当前用户缓存 // 清理缓存 清除当前租户下 所有角色的数据范围为 全部数据的 用户缓存
UserUtil.refreshUserOrgs(UserUtil.getUser().getId()); // 如果是超级管理员体系 下的用户 还需要清空超级管理员的 缓存
UserUtil.refreshUserDefOrg(UserUtil.getUser().getId()); if(TenantUtil.SUPER_ADMIN_TENANT_ID.equals(UserUtil.getTenantId())){
UserModel superAdmin = UserUtil.getUserByUserName(UserUtil.SUPER_ADMIN);
if(null != superAdmin){
// 清除缓存
this.clearCache(Collections.singletonList(superAdmin.getId()));
}
}
// 用户ID 集合
List<String> userIdList =
iUserRoleRefService.getUserIdListByTenantIdAndAllData(UserUtil.getTenantId());
// 清除缓存
this.clearCache(userIdList);
return super.insert(model); return super.insert(model);
} }
@ -337,4 +353,32 @@ public class SysOrgServiceImpl extends CrudServiceImpl<SysOrgMapper, SysOrg, Sys
throw new ServiceException(SystemMsg.EXCEPTION_ORG_USE); throw new ServiceException(SystemMsg.EXCEPTION_ORG_USE);
} }
} }
/**
*
* @param userIdList ID
*/
private void clearCache(List<String> userIdList){
if(CollUtil.isNotEmpty(userIdList)){
int cacheCount = 0;
for (String userId : userIdList) {
cacheCount += 2;
boolean tmp;
// 清空当期用户缓存 组织
tmp = UserUtil.refreshUserOrgs(userId);
if(tmp){
cacheCount--;
}
tmp = UserUtil.refreshUserDefOrg(userId);
if(tmp){
cacheCount--;
}
}
// 判断删除状态
if(cacheCount != 0){
// 删除缓存失败
throw new ServiceException(CoreMsg.CACHE_DEL_EXCEPTION);
}
}
}
} }

@ -42,6 +42,9 @@ public class SysRole extends BaseEntity {
/** 是否内置数据 0否 1是 */ /** 是否内置数据 0否 1是 */
private String izLock; private String izLock;
/** 标签 */
private String label;
/** 授权数据范围 */ /** 授权数据范围 */
private String dataScope; private String dataScope;

@ -15,7 +15,9 @@
*/ */
package org.opsli.modulars.system.role.service.impl; package org.opsli.modulars.system.role.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -25,6 +27,7 @@ import org.opsli.common.constants.MyBatisConstants;
import org.opsli.common.exception.ServiceException; import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.FieldUtil; import org.opsli.common.utils.FieldUtil;
import org.opsli.core.base.service.impl.CrudServiceImpl; import org.opsli.core.base.service.impl.CrudServiceImpl;
import org.opsli.core.msg.CoreMsg;
import org.opsli.core.persistence.querybuilder.GenQueryBuilder; import org.opsli.core.persistence.querybuilder.GenQueryBuilder;
import org.opsli.core.persistence.querybuilder.QueryBuilder; import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.persistence.querybuilder.chain.QueryDataPermsHandler; import org.opsli.core.persistence.querybuilder.chain.QueryDataPermsHandler;
@ -35,6 +38,7 @@ import org.opsli.modulars.system.role.entity.SysRole;
import org.opsli.modulars.system.role.mapper.RoleMapper; import org.opsli.modulars.system.role.mapper.RoleMapper;
import org.opsli.modulars.system.role.service.IRoleMenuRefService; import org.opsli.modulars.system.role.service.IRoleMenuRefService;
import org.opsli.modulars.system.role.service.IRoleService; import org.opsli.modulars.system.role.service.IRoleService;
import org.opsli.modulars.system.user.service.IUserRoleRefService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -56,6 +60,8 @@ public class RoleServiceImpl extends CrudServiceImpl<RoleMapper, SysRole, RoleMo
private RoleMapper mapper; private RoleMapper mapper;
@Autowired @Autowired
private IRoleMenuRefService iRoleMenuRefService; private IRoleMenuRefService iRoleMenuRefService;
@Autowired
private IUserRoleRefService iUserRoleRefService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -106,39 +112,68 @@ public class RoleServiceImpl extends CrudServiceImpl<RoleMapper, SysRole, RoleMo
throw new ServiceException(SystemMsg.EXCEPTION_ROLE_UNIQUE); throw new ServiceException(SystemMsg.EXCEPTION_ROLE_UNIQUE);
} }
return super.update(model); model = super.update(model);
// 清除缓存
if(null != model){
clearCache(Convert.toStrArray(model.getId()));
}
return model;
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public boolean delete(String id) { public boolean delete(String id) {
boolean roleUsed = iUserRoleRefService.isRoleUsed(id);
if(roleUsed){
// 角色删除失败, 改角色正在被其他用户使用
throw new ServiceException(SystemMsg.EXCEPTION_ROLE_USED);
}
// 删除角色下 权限 // 删除角色下 权限
iRoleMenuRefService.delPermsByRoleIds(Convert.toList(String.class, id)); iRoleMenuRefService.delPermsByRoleIds(Convert.toList(String.class, id));
return super.delete(id); return super.delete(id);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteAll(String[] ids) { public boolean deleteAll(String[] ids) {
boolean roleUsed = iUserRoleRefService.isRoleUsed(ids);
if(roleUsed){
// 角色删除失败, 改角色正在被其他用户使用
throw new ServiceException(SystemMsg.EXCEPTION_ROLE_USED);
}
// 删除角色下 权限 // 删除角色下 权限
iRoleMenuRefService.delPermsByRoleIds(Convert.toList(String.class, ids)); iRoleMenuRefService.delPermsByRoleIds(Convert.toList(String.class, ids));
return super.deleteAll(ids); return super.deleteAll(ids);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public boolean delete(RoleModel model) { public boolean delete(RoleModel model) {
if(model == null){ if(model == null){
return false; return false;
} }
boolean roleUsed = iUserRoleRefService.isRoleUsed(model.getId());
if(roleUsed){
// 角色删除失败, 改角色正在被其他用户使用
throw new ServiceException(SystemMsg.EXCEPTION_ROLE_USED);
}
// 删除角色下 权限 // 删除角色下 权限
iRoleMenuRefService.delPermsByRoleIds(Convert.toList(String.class, model.getId())); iRoleMenuRefService.delPermsByRoleIds(Convert.toList(String.class, model.getId()));
return super.delete(model); return super.delete(model);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteAll(Collection<RoleModel> models) { public boolean deleteAll(Collection<RoleModel> models) {
List<String> roleIds = Lists.newArrayList(); List<String> roleIds = Lists.newArrayList();
for (RoleModel model : models) { for (RoleModel model : models) {
roleIds.add(model.getId()); roleIds.add(model.getId());
} }
// 删除角色下 权限 // 删除角色下 权限
iRoleMenuRefService.delPermsByRoleIds(roleIds); iRoleMenuRefService.delPermsByRoleIds(roleIds);
return super.deleteAll(models); return super.deleteAll(models);
@ -214,6 +249,43 @@ public class RoleServiceImpl extends CrudServiceImpl<RoleMapper, SysRole, RoleMo
} }
/**
*
* @param roleIds ID
*/
private void clearCache(String[] roleIds){
// 清空该角色下 用户缓存
List<String> userIdList = iUserRoleRefService.getUserIdListByRoleIds(roleIds);
if(CollUtil.isNotEmpty(userIdList)){
int cacheCount = 0;
for (String userId : userIdList) {
cacheCount += 4;
boolean tmp;
// 清空当期用户缓存角色、权限、菜单
tmp = UserUtil.refreshUserRoles(userId);
if(tmp){
cacheCount--;
}
tmp = UserUtil.refreshUserAllPerms(userId);
if(tmp){
cacheCount--;
}
tmp = UserUtil.refreshUserMenus(userId);
if(tmp){
cacheCount--;
}
tmp = UserUtil.refreshUserDefRole(userId);
if(tmp){
cacheCount--;
}
}
// 判断删除状态
if(cacheCount != 0){
// 删除缓存失败
throw new ServiceException(CoreMsg.CACHE_DEL_EXCEPTION);
}
}
}
} }

@ -15,8 +15,11 @@
*/ */
package org.opsli.modulars.system.user.mapper; package org.opsli.modulars.system.user.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.opsli.modulars.system.menu.entity.SysMenu; import org.opsli.modulars.system.menu.entity.SysMenu;
import org.opsli.modulars.system.user.entity.SysUserRoleRef; import org.opsli.modulars.system.user.entity.SysUserRoleRef;
@ -67,11 +70,12 @@ public interface UserRoleRefMapper extends BaseMapper<SysUserRoleRef> {
List<SysMenu> findMenuAllListByUserId(String userId); List<SysMenu> findMenuAllListByUserId(String userId);
/** /**
* ID Id * Id
* @param roleId ID *
* @param wrapper wrapper
* @return List * @return List
*/ */
List<String> getUserIdListByRoleId(String roleId); List<String> getUserIdList(@Param(Constants.WRAPPER) Wrapper<?> wrapper);
/** /**
* ID Id * ID Id

@ -66,6 +66,8 @@
and c.type in ( '1', '3' ) and c.type in ( '1', '3' )
and c.deleted = '0' and c.deleted = '0'
and c.hidden = '0' and c.hidden = '0'
<!-- 0:系统模块 1:功能模块 -->
and c.label like '%1%'
</select> </select>
<!-- 根据用户id查询菜单列表--> <!-- 根据用户id查询菜单列表-->
@ -95,16 +97,13 @@
and c.hidden = '0' and c.hidden = '0'
</select> </select>
<select id="getUserIdListByRoleId" resultType="String"> <select id="getUserIdList" resultType="String">
select select
a.user_id a.user_id
from from sys_user_role_ref a
sys_user_role_ref a
join sys_user b on a.user_id = b.id join sys_user b on a.user_id = b.id
<where> join sys_role c on a.role_id = c.id
b.deleted = 0 ${ew.customSqlSegment}
and a.role_id = #{roleId}
</where>
</select> </select>
<select id="getUserIdListByMenuId" resultType="String"> <select id="getUserIdListByMenuId" resultType="String">

@ -61,9 +61,10 @@ public interface IUserRoleRefService {
/** /**
* ID * ID
* @param userId ID * @param userId ID
* @param label
* @return List * @return List
*/ */
List<MenuModel> getMenuAllListByUserId(String userId); List<MenuModel> getMenuAllListByUserId(String userId, String label);
/** /**
* ID Id * ID Id
@ -72,6 +73,20 @@ public interface IUserRoleRefService {
*/ */
List<String> getUserIdListByRoleId(String roleId); List<String> getUserIdListByRoleId(String roleId);
/**
* ID Id
* @param roleIds ID
* @return List
*/
List<String> getUserIdListByRoleIds(String[] roleIds);
/**
* ID ID
* @param tenantId ID
* @return List
*/
List<String> getUserIdListByTenantIdAndAllData(String tenantId);
/** /**
* ID Id * ID Id
* @param roleId ID * @param roleId ID
@ -100,4 +115,20 @@ public interface IUserRoleRefService {
*/ */
boolean setRoles(UserRoleRefModel model); boolean setRoles(UserRoleRefModel model);
/**
* 使
* @param roleId ID
* @return boolean
*/
boolean isRoleUsed(String roleId);
/**
* 使
* @param roleIds ID
* @return boolean
*/
boolean isRoleUsed(String[] roleIds);
} }

@ -17,6 +17,8 @@ package org.opsli.modulars.system.user.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@ -26,8 +28,10 @@ import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.role.RoleModel; import org.opsli.api.wrapper.system.role.RoleModel;
import org.opsli.api.wrapper.system.user.UserModel; import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.api.wrapper.system.user.UserRoleRefModel; import org.opsli.api.wrapper.system.user.UserRoleRefModel;
import org.opsli.common.constants.MyBatisConstants;
import org.opsli.common.enums.DictType; import org.opsli.common.enums.DictType;
import org.opsli.common.exception.ServiceException; import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.FieldUtil;
import org.opsli.common.utils.ListDistinctUtil; import org.opsli.common.utils.ListDistinctUtil;
import org.opsli.common.utils.WrapperUtil; import org.opsli.common.utils.WrapperUtil;
import org.opsli.core.msg.CoreMsg; import org.opsli.core.msg.CoreMsg;
@ -101,7 +105,7 @@ public class UserRoleRefServiceImpl extends ServiceImpl<UserRoleRefMapper, SysUs
QueryWrapper<SysMenu> queryWrapper = queryBuilder.build(); QueryWrapper<SysMenu> queryWrapper = queryBuilder.build();
queryWrapper.notIn("parent_id", -1); queryWrapper.notIn("parent_id", -1);
queryWrapper.eq("type", '2'); queryWrapper.eq("type", '2');
queryWrapper.eq("hidden", '0'); queryWrapper.eq("hidden", DictType.NO_YES_NO.getValue());
List<SysMenu> menuList = iMenuService.findList(queryWrapper); List<SysMenu> menuList = iMenuService.findList(queryWrapper);
for (SysMenu sysMenu : menuList) { for (SysMenu sysMenu : menuList) {
perms.add(sysMenu.getPermissions()); perms.add(sysMenu.getPermissions());
@ -129,7 +133,8 @@ public class UserRoleRefServiceImpl extends ServiceImpl<UserRoleRefMapper, SysUs
QueryWrapper<SysMenu> queryWrapper = queryBuilder.build(); QueryWrapper<SysMenu> queryWrapper = queryBuilder.build();
queryWrapper.notIn("parent_id", -1); queryWrapper.notIn("parent_id", -1);
queryWrapper.in("type", '1', '3'); queryWrapper.in("type", '1', '3');
queryWrapper.eq("hidden", '0'); queryWrapper.eq("hidden", DictType.NO_YES_NO.getValue());
queryWrapper.like("label",DictType.MENU_LABEL_SYSTEM.getValue());
menuList = iMenuService.findList(queryWrapper); menuList = iMenuService.findList(queryWrapper);
}else{ }else{
menuList = mapper.findMenuListByUserId(userId); menuList = mapper.findMenuListByUserId(userId);
@ -143,7 +148,7 @@ public class UserRoleRefServiceImpl extends ServiceImpl<UserRoleRefMapper, SysUs
} }
@Override @Override
public List<MenuModel> getMenuAllListByUserId(String userId) { public List<MenuModel> getMenuAllListByUserId(String userId, String label) {
UserModel userModel = iUserService.get(userId); UserModel userModel = iUserService.get(userId);
if(userModel == null){ if(userModel == null){
@ -156,7 +161,8 @@ public class UserRoleRefServiceImpl extends ServiceImpl<UserRoleRefMapper, SysUs
QueryBuilder<SysMenu> queryBuilder = new GenQueryBuilder<>(); QueryBuilder<SysMenu> queryBuilder = new GenQueryBuilder<>();
QueryWrapper<SysMenu> queryWrapper = queryBuilder.build(); QueryWrapper<SysMenu> queryWrapper = queryBuilder.build();
queryWrapper.notIn("parent_id", -1); queryWrapper.notIn("parent_id", -1);
queryWrapper.eq("hidden", '0'); queryWrapper.eq("hidden", DictType.NO_YES_NO.getValue());
queryWrapper.like("label", label);
menuList = iMenuService.findList(queryWrapper); menuList = iMenuService.findList(queryWrapper);
}else{ }else{
menuList = mapper.findMenuAllListByUserId(userId); menuList = mapper.findMenuAllListByUserId(userId);
@ -175,7 +181,45 @@ public class UserRoleRefServiceImpl extends ServiceImpl<UserRoleRefMapper, SysUs
@Override @Override
public List<String> getUserIdListByRoleId(String roleId) { public List<String> getUserIdListByRoleId(String roleId) {
List<String> users = mapper.getUserIdListByRoleId(roleId); QueryWrapper<SysUserRoleRef> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(
FieldUtil.humpToUnderline(MyBatisConstants.FIELD_DELETE_LOGIC), DictType.NO_YES_NO.getValue());
queryWrapper.eq("role_id", roleId);
List<String> users = mapper.getUserIdList(queryWrapper);
if(CollUtil.isEmpty(users)){
return ListUtil.empty();
}
// 去重
return ListDistinctUtil.distinct(users);
}
@Override
public List<String> getUserIdListByRoleIds(String[] roleIds) {
QueryWrapper<SysUserRoleRef> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(
FieldUtil.humpToUnderline(MyBatisConstants.FIELD_DELETE_LOGIC), DictType.NO_YES_NO.getValue());
queryWrapper.in("role_id", Convert.toList(roleIds));
List<String> users = mapper.getUserIdList(queryWrapper);
if(CollUtil.isEmpty(users)){
return ListUtil.empty();
}
// 去重
return ListDistinctUtil.distinct(users);
}
@Override
public List<String> getUserIdListByTenantIdAndAllData(String tenantId) {
QueryWrapper<SysUserRoleRef> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(
FieldUtil.humpToUnderline(MyBatisConstants.FIELD_DELETE_LOGIC), DictType.NO_YES_NO.getValue());
queryWrapper.eq("c.tenantId", tenantId);
queryWrapper.eq("c.data_scope", "3");
List<String> users = mapper.getUserIdList(queryWrapper);
if(CollUtil.isEmpty(users)){ if(CollUtil.isEmpty(users)){
return ListUtil.empty(); return ListUtil.empty();
} }
@ -253,6 +297,30 @@ public class UserRoleRefServiceImpl extends ServiceImpl<UserRoleRefMapper, SysUs
return true; return true;
} }
@Override
public boolean isRoleUsed(String roleId) {
if(StringUtils.isBlank(roleId)){
return false;
}
QueryWrapper<SysUserRoleRef> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("role_id", roleId);
return this.count(queryWrapper) == 0;
}
@Override
public boolean isRoleUsed(String[] roleIds) {
if(ArrayUtil.isEmpty(roleIds)){
return false;
}
QueryWrapper<SysUserRoleRef> queryWrapper = new QueryWrapper<>();
queryWrapper.in("role_id", Convert.toList(roleIds));
return this.count(queryWrapper) == 0;
}
// =========== // ===========

@ -99,6 +99,7 @@ public class UserServiceImpl extends CrudServiceImpl<UserMapper, SysUser, UserMo
if(!UserUtil.isHasUpdateTenantPerms(UserUtil.getUser())){ if(!UserUtil.isHasUpdateTenantPerms(UserUtil.getUser())){
model.setTenantId(null); model.setTenantId(null);
model.setIzTenantAdmin(null); model.setIzTenantAdmin(null);
model.setEnableSwitchTenant(null);
} }
} }

@ -31,6 +31,7 @@ import org.opsli.api.web.system.user.UserApi;
import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.menu.MenuModel;
import org.opsli.api.wrapper.system.options.OptionsModel; import org.opsli.api.wrapper.system.options.OptionsModel;
import org.opsli.api.wrapper.system.role.RoleModel; import org.opsli.api.wrapper.system.role.RoleModel;
import org.opsli.api.wrapper.system.tenant.TenantModel;
import org.opsli.api.wrapper.system.user.*; import org.opsli.api.wrapper.system.user.*;
import org.opsli.common.annotation.ApiRestController; import org.opsli.common.annotation.ApiRestController;
import org.opsli.common.annotation.EnableLog; import org.opsli.common.annotation.EnableLog;
@ -49,8 +50,10 @@ import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.persistence.querybuilder.WebQueryBuilder; import org.opsli.core.persistence.querybuilder.WebQueryBuilder;
import org.opsli.core.utils.OptionsUtil; import org.opsli.core.utils.OptionsUtil;
import org.opsli.core.utils.OrgUtil; import org.opsli.core.utils.OrgUtil;
import org.opsli.core.utils.TenantUtil;
import org.opsli.core.utils.UserUtil; import org.opsli.core.utils.UserUtil;
import org.opsli.modulars.system.SystemMsg; import org.opsli.modulars.system.SystemMsg;
import org.opsli.modulars.system.tenant.entity.SysTenant;
import org.opsli.modulars.system.user.entity.SysUser; import org.opsli.modulars.system.user.entity.SysUser;
import org.opsli.modulars.system.user.entity.SysUserWeb; import org.opsli.modulars.system.user.entity.SysUserWeb;
import org.opsli.modulars.system.user.service.IUserRoleRefService; import org.opsli.modulars.system.user.service.IUserRoleRefService;
@ -59,6 +62,7 @@ import org.opsli.plugins.oss.OssStorageFactory;
import org.opsli.plugins.oss.service.BaseOssStorageService; import org.opsli.plugins.oss.service.BaseOssStorageService;
import org.opsli.plugins.oss.service.OssStorageService; import org.opsli.plugins.oss.service.OssStorageService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -524,4 +528,85 @@ public class UserRestController extends BaseRestController<SysUser, UserModel, I
} }
/**
*
* @param tenantId ID
* @return ResultVo
*/
@ApiOperation(value = "切换租户", notes = "切换租户")
@GetMapping("/switchTenant")
public ResultVo<?> switchTenant(String tenantId) {
UserModel currUser = UserUtil.getUser();
if (!DictType.NO_YES_YES.getValue().equals(currUser.getEnableSwitchTenant())){
// 不允许切换租户
throw new ServiceException(SystemMsg.EXCEPTION_USER_SWITCH_NOT_ALLOWED);
}
// 验证租户是否生效
TenantModel tenant = TenantUtil.getTenant(tenantId);
if(tenant == null){
throw new ServiceException(TokenMsg.EXCEPTION_LOGIN_TENANT_NOT_USABLE);
}
// 被切换租户的 管理员用户 取一个
SysUser isSwitchedUser = IService.getOne(new QueryWrapper<SysUser>()
.eq("iz_tenant_admin", DictType.NO_YES_YES.getValue())
.eq(FieldUtil.humpToUnderline(MyBatisConstants.FIELD_DELETE_LOGIC), DictType.NO_YES_NO.getValue())
.eq(FieldUtil.humpToUnderline(MyBatisConstants.FIELD_TENANT), tenantId)
.last("limit 1")
);
if (isSwitchedUser == null){
// 此租户不存在管理员,不能切换
throw new ServiceException(SystemMsg.EXCEPTION_USER_SWITCH_TENANT_NOT_HAS_ADMIN);
}
// 检测用户是否有角色
List<String> roleModelList = UserUtil.getUserRolesByUserId(isSwitchedUser.getId());
if(CollUtil.isEmpty(roleModelList)){
// 用户暂无角色,请设置后登录
throw new ServiceException(TokenMsg.EXCEPTION_USER_ROLE_NOT_NULL);
}
// 检测用户是否有角色菜单
List<MenuModel> menuModelList = UserUtil.getMenuListByUserId(isSwitchedUser.getId());
if(CollUtil.isEmpty(menuModelList)){
// 用户暂无角色菜单,请设置后登录
throw new ServiceException(TokenMsg.EXCEPTION_USER_MENU_NOT_NULL);
}
// 检测用户是否有角色权限
List<String> userAllPermsList = UserUtil.getUserAllPermsByUserId(isSwitchedUser.getId());
if(CollUtil.isEmpty(userAllPermsList)){
// 用户暂无角色菜单,请设置后登录
throw new ServiceException(TokenMsg.EXCEPTION_USER_PERMS_NOT_NULL);
}
// 更新 当前用户缓存
currUser.setSwitchTenantId(tenantId);
currUser.setSwitchTenantUserId(isSwitchedUser.getId());
return UserUtil.updateUser(currUser)
? ResultVo.success("切换租户成功")
: ResultVo.error("切换租户失败");
}
/**
*
* @return ResultVo
*/
@ApiOperation(value = "切换回自己账户", notes = "切换回自己账户")
@GetMapping("/switchOneself")
public ResultVo<?> switchOneself() {
UserModel currUser = UserUtil.getUser();
currUser.setSwitchTenantId(null);
currUser.setSwitchTenantUserId(null);
return UserUtil.updateUser(currUser)
? ResultVo.success("切换成功")
: ResultVo.error("切换失败");
}
} }

@ -22,6 +22,7 @@ import org.opsli.plugins.redis.pushsub.entity.BaseSubMessage;
import org.opsli.plugins.redis.scripts.RedisScriptCache; import org.opsli.plugins.redis.scripts.RedisScriptCache;
import org.opsli.plugins.redis.scripts.enums.RedisScriptsEnum; import org.opsli.plugins.redis.scripts.enums.RedisScriptsEnum;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
@ -1509,6 +1510,20 @@ public class RedisPlugin {
destKey); destKey);
} }
/**
* pipeline
*
*/
public List<Object> getPileLineList(List<String> cacheList) {
return redisTemplate.executePipelined((RedisConnection connection) -> {
connection.openPipeline();
for (String key : cacheList) {
connection.hGetAll(key.getBytes());
}
return null;
});
}
// ===================== 消息发布 ===================== // ===================== 消息发布 =====================
/** /**

Loading…
Cancel
Save