去除 LoginUser 的 roleIds、deptId 字段,简化

This commit is contained in:
YunaiV
2022-05-07 00:39:39 +08:00
parent d8a242629b
commit 8737674d74
16 changed files with 179 additions and 189 deletions

View File

@@ -26,12 +26,13 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserRoleIds;
import static java.util.Collections.singleton;
@Api(tags = "管理后台 - 认证")
@RestController
@@ -69,12 +70,12 @@ public class AuthController {
return null;
}
// 获得角色列表
List<RoleDO> roleList = roleService.getRolesFromCache(getLoginUserRoleIds());
Set<Long> roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
List<RoleDO> roleList = roleService.getRolesFromCache(roleIds);
// 获得菜单列表
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()),
SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus()));
singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
// 拼接结果返回
return success(AuthConvert.INSTANCE.convert(user, roleList, menuList));
}
@@ -82,11 +83,12 @@ public class AuthController {
@GetMapping("/list-menus")
@ApiOperation("获得登录用户的菜单列表")
public CommonResult<List<AuthMenuRespVO>> getMenus() {
// 获得角色列表
Set<Long> roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
// 获得用户拥有的菜单列表
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型
SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
// 转换成 Tree 结构返回
return success(AuthConvert.INSTANCE.buildMenuTree(menuList));
}

View File

@@ -1,15 +1,16 @@
package cn.iocoder.yudao.module.system.controller.admin.auth;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageItemRespVO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageReqVO;
import cn.iocoder.yudao.module.system.convert.auth.UserSessionConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.auth.UserSessionService;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.system.service.auth.UserSessionService;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.annotations.Api;
@@ -49,7 +50,8 @@ public class UserSessionController {
// 获得拼接需要的数据
Map<Long, AdminUserDO> userMap = userService.getUserMap(
convertList(pageResult.getList(), UserSessionDO::getUserId));
convertList(pageResult.getList(), UserSessionDO::getUserId,
session -> session.getUserType().equals(UserTypeEnum.ADMIN.getValue())));
Map<Long, DeptDO> deptMap = deptService.getDeptMap(
convertList(userMap.values(), AdminUserDO::getDeptId));
// 拼接结果返回

View File

@@ -17,7 +17,6 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.system.service.common.CaptchaService;
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import lombok.extern.slf4j.Slf4j;
@@ -36,12 +35,10 @@ import org.springframework.util.Assert;
import javax.annotation.Resource;
import javax.validation.Validator;
import java.util.Objects;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static java.util.Collections.singleton;
/**
* Auth Service 实现类
@@ -60,8 +57,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // UserService 存在重名
private AdminUserService userService;
@Resource
private PermissionService permissionService;
@Resource
private CaptchaService captchaService;
@Resource
private LoginLogService loginLogService;
@@ -211,16 +206,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
}
}
/**
* 获得 User 拥有的角色编号数组
*
* @param userId 用户编号
* @return 角色编号数组
*/
private Set<Long> getUserRoleIds(Long userId) {
return permissionService.getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
}
@Override
public String socialQuickLogin(AuthSocialQuickLoginReqVO reqVO, String userIp, String userAgent) {
// 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
@@ -318,17 +303,13 @@ public class AdminAuthServiceImpl implements AdminAuthService {
}
// 刷新 LoginUser 缓存
LoginUser newLoginUser= this.buildLoginUser(user);
LoginUser newLoginUser= buildLoginUser(user);
userSessionService.refreshUserSession(token, newLoginUser);
return newLoginUser;
}
private LoginUser buildLoginUser(AdminUserDO user) {
LoginUser loginUser = AuthConvert.INSTANCE.convert(user);
// 补全字段
loginUser.setDeptId(user.getDeptId());
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
return loginUser;
return AuthConvert.INSTANCE.convert(user);
}
}

View File

@@ -3,12 +3,12 @@ package cn.iocoder.yudao.module.system.service.permission;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
@@ -22,6 +22,8 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
@@ -36,6 +38,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.function.Supplier;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static java.util.Collections.singleton;
/**
* 权限 Service 实现类
@@ -46,11 +52,6 @@ import java.util.*;
@Slf4j
public class PermissionServiceImpl implements PermissionService {
/**
* LoginUser 的 Context 缓存 Key
*/
public static final String CONTEXT_KEY = PermissionServiceImpl.class.getSimpleName();
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高
@@ -93,6 +94,8 @@ public class PermissionServiceImpl implements PermissionService {
private MenuService menuService;
@Resource
private DeptService deptService;
@Resource
private AdminUserService userService;
@Resource
private PermissionProducer permissionProducer;
@@ -319,7 +322,7 @@ public class PermissionServiceImpl implements PermissionService {
}
// 获得当前登录的角色。如果为空,说明没有权限
Set<Long> roleIds = SecurityFrameworkUtils.getLoginUserRoleIds();
Set<Long> roleIds = getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
if (CollUtil.isEmpty(roleIds)) {
return false;
}
@@ -354,7 +357,7 @@ public class PermissionServiceImpl implements PermissionService {
}
// 获得当前登录的角色。如果为空,说明没有权限
Set<Long> roleIds = SecurityFrameworkUtils.getLoginUserRoleIds();
Set<Long> roleIds = getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
if (CollUtil.isEmpty(roleIds)) {
return false;
}
@@ -368,16 +371,18 @@ public class PermissionServiceImpl implements PermissionService {
}
@Override
public DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser) {
// 判断是否 context 已经缓存
DeptDataPermissionRespDTO result = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class);
if (result != null) {
@DataPermission(enable = false) // 关闭数据权限,不然就会出现递归获取数据权限的问题
public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) {
DeptDataPermissionRespDTO result = new DeptDataPermissionRespDTO();
// 获得用户的角色
Set<Long> roleIds = getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
if (CollUtil.isEmpty(roleIds)) {
return result;
}
// 创建 DeptDataPermissionRespDTO 对象
result = new DeptDataPermissionRespDTO();
List<RoleDO> roles = roleService.getRolesFromCache(loginUser.getRoleIds());
List<RoleDO> roles = roleService.getRolesFromCache(roleIds);
// 获得用户的部门编号的缓存,通过 Guava 的 Suppliers 惰性求值,即有且仅有第一次发起 DB 的查询
Supplier<Long> userDeptIdCache = Suppliers.memoize(() -> userService.getUser(userId).getDeptId());
// 遍历每个角色,计算
for (RoleDO role : roles) {
// 为空时,跳过
if (role.getDataScope() == null) {
@@ -393,20 +398,20 @@ public class PermissionServiceImpl implements PermissionService {
CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds());
// 自定义可见部门时,保证可以看到自己所在的部门。否则,一些场景下可能会有问题。
// 例如说,登录时,基于 t_user 的 username 查询会可能被 dept_id 过滤掉
CollUtil.addAll(result.getDeptIds(), loginUser.getDeptId());
CollUtil.addAll(result.getDeptIds(), userDeptIdCache.get());
continue;
}
// 情况三DEPT_ONLY
if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) {
CollectionUtils.addIfNotNull(result.getDeptIds(), loginUser.getDeptId());
CollectionUtils.addIfNotNull(result.getDeptIds(), userDeptIdCache.get());
continue;
}
// 情况四DEPT_DEPT_AND_CHILD
if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) {
List<DeptDO> depts = deptService.getDeptsByParentIdFromCache(loginUser.getDeptId(), true);
List<DeptDO> depts = deptService.getDeptsByParentIdFromCache(userDeptIdCache.get(), true);
CollUtil.addAll(result.getDeptIds(), CollectionUtils.convertList(depts, DeptDO::getId));
//添加本身部门id
CollUtil.addAll(result.getDeptIds(), loginUser.getDeptId());
// 添加本身部门编号
CollUtil.addAll(result.getDeptIds(), userDeptIdCache.get());
continue;
}
// 情况五SELF
@@ -415,11 +420,8 @@ public class PermissionServiceImpl implements PermissionService {
continue;
}
// 未知情况error log 即可
log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", loginUser.getId(), JsonUtils.toJsonString(result));
log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", userId, JsonUtils.toJsonString(result));
}
// 添加到缓存,并返回
loginUser.setContext(CONTEXT_KEY, result);
return result;
}

View File

@@ -81,6 +81,7 @@ public class TenantServiceImpl implements TenantService {
@Getter
private volatile Date maxUpdateTime;
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
@Autowired(required = false) // 由于 yudao.tenant.enable 配置项,可以关闭多租户的功能,所以这里只能不强制注入
private TenantProperties tenantProperties;

View File

@@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -61,6 +62,7 @@ public class AdminUserServiceImpl implements AdminUserService {
@Resource
private PasswordEncoder passwordEncoder;
@Resource
@Lazy // 延迟,避免循环依赖报错
private TenantService tenantService;
@Resource