1、新增管理等登录入口,菜单权限根据登录入口分别展示;2、菜单新增来源类型属性;

This commit is contained in:
gaoqr
2025-08-06 12:00:06 +08:00
parent fdb119f672
commit 33cb942814
23 changed files with 303 additions and 45 deletions
@@ -14,11 +14,9 @@ public class ErrorCodeConstants {
public static final ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_002_000_001, "登录失败,账号被禁用");
public static final ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_004, "验证码不正确,原因:{}");
public static final ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_002_000_005, "未绑定账号,需要进行绑定");
public static final ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1_002_000_006, "Token 已经过期");
public static final ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_007, "手机号不存在");
public static final ErrorCode AUTH_MOBILE_NO_CHANGE = new ErrorCode(1_002_000_008, "手机号未发生改变,无需修改");
public static final ErrorCode AUTH_LOGIN_GEO_UNCORRECT = new ErrorCode(1_002_000_009, "登录失败,请前往机构登记地址登录系统");
public static final ErrorCode AUTH_LOGIN_ORG_GEO_EMPTY = new ErrorCode(1_002_000_010, "当前组织地址未登记,请联系组织管理员");
public static final ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_006, "手机号不存在");
public static final ErrorCode AUTH_MOBILE_NO_CHANGE = new ErrorCode(1_002_000_007, "手机号未发生改变,无需修改");
public static final ErrorCode AUTH_MANAGEENDPOINT_LOGIN_PERMISSION_ERROR = new ErrorCode(1_002_000_008, "登录失败,管理端账号不存在");
// ========== 菜单模块 1-002-001-000 ==========
public static final ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1_002_001_000, "已经存在该名字的菜单");
@@ -27,6 +25,7 @@ public class ErrorCodeConstants {
public static final ErrorCode MENU_NOT_EXISTS = new ErrorCode(1_002_001_003, "菜单不存在");
public static final ErrorCode MENU_EXISTS_CHILDREN = new ErrorCode(1_002_001_004, "存在子菜单,无法删除");
public static final ErrorCode MENU_PARENT_NOT_DIR_OR_MENU = new ErrorCode(1_002_001_005, "父菜单的类型必须是目录或者菜单");
public static final ErrorCode MANAGEMENT_MENU_OPERATION_PERMISSION_ERROR = new ErrorCode(1_002_001_006, "管理端菜单操作权限不足");
// ========== 角色模块 1-002-002-000 ==========
public static final ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1_002_002_000, "角色不存在");
@@ -34,7 +33,7 @@ public class ErrorCodeConstants {
public static final ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1_002_002_002, "已经存在编码为【{}】的角色");
public static final ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1_002_002_003, "不能操作类型为系统内置的角色");
public static final ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "名字为【{}】的角色已被禁用");
public static final ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "编码【{}】不能使用");
public static final ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "编码【{}】不能使用");
public static final ErrorCode ROLE_ME_ERROR = new ErrorCode(1_002_002_006, "不可为自身分配角色");
public static final ErrorCode ROLE_NOT_SUPERADMIN_NO_ORGAN_ID_OPER_ERROR = new ErrorCode(1_002_002_007, "非超管分配权限");
public static final ErrorCode BUILDIN_ROLE_MODIFY_PERMISSION_ERROR = new ErrorCode(1_002_002_008, "修改内置角色下菜单权限的权限不足");
@@ -0,0 +1,30 @@
package com.cf.imes.module.system.enums.permission;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 菜单来源类型枚举类
*
* @author 晨丰科技
*/
@Getter
@AllArgsConstructor
public enum MenuSourceTypeEnum {
/**
* 生产端
*/
PRODUCTION(1),
/**
* 管理端
*/
MANAGEMENT(2);
/**
* 类型
*/
private final Integer type;
}
@@ -43,7 +43,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -92,18 +91,20 @@ public class AuthController {
@Resource
private IPQueryService ipQueryService;
/**
* ip服务开关,默认为 false不开启
*/
@Value("${chenfeng.ipquery.enable:false}")
private boolean ipQueryEnable;
@PostMapping("/manage/login")
@PermitAll
@Operation(summary = "使用账号密码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> manageEndPointlogin(@Valid @RequestBody AuthLoginReqVO reqVO) {
return success(authService.login(reqVO, true));
}
@PostMapping("/login")
@PermitAll
@Operation(summary = "使用账号密码登录")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<AuthLoginRespVO> login(@Valid @RequestBody AuthLoginReqVO reqVO) {
return success(authService.login(reqVO));
return success(authService.login(reqVO, false));
}
@GetMapping("/login/check")
@@ -177,7 +178,12 @@ public class AuthController {
// 1.3 获得菜单列表
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId2(convertSet(roles, RoleDO::getId), loginUser.getOrganId());
List<MenuDO> menuList = menuService.getMenuList1(menuIds);
List<MenuDO> menuList;
if(SecurityFrameworkUtils.isManageEndPoint()){
menuList = menuService.getManageEndPointMenuList(menuIds);
} else {
menuList = menuService.getCustomEndPointMenuList(menuIds);
}
menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单
// 2. 拼接结果返回
@@ -19,7 +19,10 @@ import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static com.cf.imes.framework.common.pojo.CommonResult.success;
@@ -65,9 +68,9 @@ public class DeptController {
return success(BeanUtils.toBean(list, DeptRespVO.class));
}
@GetMapping(value = {"/list-all-simple", "/simple-list"})
@GetMapping(value = "/list-all-simple")
@Operation(summary = "获取部门精简信息列表", description = "只包含被开启的部门,主要用于前端的下拉选项")
public CommonResult<List<DeptSimpleRespVO>> getSimpleDeptList(@Valid DeptListReqVO reqVO) {
public CommonResult<List<DeptSimpleRespVO>> getAllSimpleDeptList(@Valid DeptListReqVO reqVO) {
// 有效部门的请求,传入organid就查对应的,没有就查登录人下的
DeptListReqVO efficDeptReqVO = new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus());
if (ObjectUtils.allNotNull(reqVO, reqVO.getOrganId())) {
@@ -77,6 +80,16 @@ public class DeptController {
return success(BeanUtils.toBean(deptService.removeUnowndDept(list), DeptSimpleRespVO.class));
}
@GetMapping(value = "/simple-list")
@Operation(summary = "获取部门精简信息列表", description = "只包含被开启的部门,主要用于前端的下拉选项")
public CommonResult<List<DeptSimpleRespVO>> getSimpleDeptList(@Valid DeptListReqVO reqVO) {
if (Objects.isNull(reqVO.getOrganId())) {
return success(new ArrayList<>());
}
List<DeptDO> list = deptService.getDeptList(reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()));
return success(BeanUtils.toBean(deptService.removeUnowndDept(list), DeptSimpleRespVO.class));
}
@GetMapping("/get")
@Operation(summary = "获得部门信息")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@@ -77,6 +77,36 @@ public class MenuController {
return success(true);
}
@GetMapping("/custom/list")
@Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面")
@PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
public CommonResult<List<MenuRespVO>> getCustomMenuList() {
List <MenuDO> list;
LoginUser loginUser = getLoginUser();
if (ObjectUtil.isNull(loginUser)) {
throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED);
}
AdminUserDO user = userService.getUser(loginUser.getId());
if (user == null) {
return success(new ArrayList<>());
}
// 获取登录用户所属角色
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(loginUser.getId());
if (CollUtil.isEmpty(roleIds)) {
return success(new ArrayList<>());
}
// 查询角色并过滤无效的
List<RoleDO> roles = roleService.getRoleList1(roleIds);
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
// 查询角色拥有权限的菜单id
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId2(convertSet(roles, RoleDO::getId), loginUser.getOrganId());
list = menuService.getCustomEndPointMenuList(menuIds);
list.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单
list.sort(Comparator.comparing(MenuDO::getSort));
return success(BeanUtils.toBean(list, MenuRespVO.class));
}
@GetMapping("/list")
@Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面")
@PreAuthorize("@ss.hasAnyPermissions('system:menu:query','base:permission:assign-role-menu','system:permission:assign-role-menu')")
@@ -21,4 +21,8 @@ public class MenuListReqVO {
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
@CommonStatus
private Integer visiable;
@Schema(description = "菜单来源,参见 MenuSourceTypeEnum 枚举类", example = "1")
@CommonStatus
private Integer sourceType;
}
@@ -69,4 +69,6 @@ public class MenuRespVO {
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
private LocalDateTime createTime;
@Schema(description = "菜单来源类型", example = "1")
private Integer sourceType;
}
@@ -2,6 +2,7 @@ package com.cf.imes.module.system.controller.admin.permission.vo.menu;
import com.cf.imes.framework.common.validation.NumberValid;
import com.cf.imes.module.system.validation.common.CommonStatus;
import com.cf.imes.module.system.validation.menu.MenuSourceTypeValid;
import com.cf.imes.module.system.validation.menu.MenuTypeValid;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -74,4 +75,9 @@ public class MenuSaveVO {
@Schema(description = "权限功能描述")
private String description;
@Schema(description = "菜单来源类型 ,见 MenuSourceTypeValid 枚举",example = "1")
@NotNull
@MenuSourceTypeValid
private Integer sourceType;
}
@@ -112,5 +112,8 @@ public class MenuDO extends BaseDO {
*/
private String description;
/**
* 来源类型
*/
private Integer sourceType;
}
@@ -2,6 +2,7 @@ package com.cf.imes.module.system.dal.dataobject.user;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.enums.UserTypeEnum;
import com.cf.imes.framework.mybatis.core.type.JsonLongSetTypeHandler;
import com.cf.imes.framework.organ.core.db.OrganBaseDO;
import com.cf.imes.module.system.enums.common.SexEnum;
@@ -117,4 +118,16 @@ public class AdminUserDO extends OrganBaseDO {
*/
@TableField(exist = false)
private String grayDefaultVersion;
/**
* 是否超级管理员
*/
@TableField(exist = false)
private boolean isSuperAdmin;
/**
* 用户类型
*/
@TableField(exist = false)
private UserTypeEnum userType;
}
@@ -23,7 +23,8 @@ public interface MenuMapper extends BaseMapperX<MenuDO> {
return selectList(new LambdaQueryWrapperX<MenuDO>()
.likeIfPresent(MenuDO::getName, reqVO.getName())
.eqIfPresent(MenuDO::getStatus, reqVO.getStatus())
.eqIfPresent(MenuDO::getVisible, reqVO.getVisiable()));
.eqIfPresent(MenuDO::getVisible, reqVO.getVisiable())
.eqIfPresent(MenuDO::getSourceType, reqVO.getSourceType()));
}
default List<MenuDO> selectListByPermission(String permission) {
@@ -70,10 +70,11 @@ public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
LambdaQueryWrapperX<AdminUserDO> lambdaQueryWrapperX = new LambdaQueryWrapperX<>();
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
assert loginUser != null;
Boolean isSupAdmin = loginUser.getIsSupAdmin();
if(isSupAdmin && !Objects.isNull(reqVO.getOrganId())) {
lambdaQueryWrapperX.eqIfPresent(AdminUserDO::getOrganId, reqVO.getOrganId());
}else{
if (SecurityFrameworkUtils.isCfOrg()) {
if (!Objects.isNull(reqVO.getOrganId())) {
lambdaQueryWrapperX.eqIfPresent(AdminUserDO::getOrganId, reqVO.getOrganId());
}
} else {
lambdaQueryWrapperX.eqIfPresent(AdminUserDO::getOrganId, loginUser.getOrganId());
}
return selectPage(reqVO, lambdaQueryWrapperX
@@ -31,9 +31,10 @@ public interface AdminAuthService {
* 账号登录
*
* @param reqVO 登录信息
* @param isManageEndPoint 是否为管理端登录
* @return 登录结果
*/
AuthLoginRespVO login(@Valid AuthLoginReqVO reqVO);
AuthLoginRespVO login(@Valid AuthLoginReqVO reqVO, boolean isManageEndPoint);
/**
* 登录校验
@@ -6,6 +6,7 @@ import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.enums.UserTypeEnum;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
import com.cf.imes.framework.common.util.monitor.TracerUtils;
import com.cf.imes.framework.common.util.servlet.ServletUtils;
@@ -14,6 +15,8 @@ import com.cf.imes.framework.ip.core.service.IPQueryService;
import com.cf.imes.framework.ip.core.service.dto.IPQueryDataRespDTO;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.framework.organ.core.service.OrganFrameworkService;
import com.cf.imes.framework.security.core.service.SecurityFrameworkService;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.system.api.logger.dto.LoginLogCreateReqDTO;
import com.cf.imes.module.system.api.sms.SmsCodeApi;
import com.cf.imes.module.system.api.social.dto.SocialUserRespDTO;
@@ -97,6 +100,9 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private SecurityFrameworkService securityFrameworkService;
/**
* 验证码的开关,默认为 true
*/
@@ -118,7 +124,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
AdminUserDO user = userService.getUserUniqueByUserName(username);
// 校验用户是否存在
if (user == null) {
createLoginLog(null, username, null, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
createLoginLog(null, username, null, null, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
throw ServiceExceptionUtil.exception(ErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS);
}
Long organId = user.getOrganId();
@@ -129,12 +135,12 @@ public class AdminAuthServiceImpl implements AdminAuthService {
organFrameworkService.validDept(user.getDeptId());
// 校验密码
if (!userService.isPasswordMatch(password, user.getPassword())) {
createLoginLog(user.getId(), username, organId, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
createLoginLog(user.getId(), username, null, organId, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
throw ServiceExceptionUtil.exception(ErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS);
}
// 校验是否禁用
if (CommonStatusEnum.isDisable(user.getStatus())) {
createLoginLog(user.getId(), username, organId, logTypeEnum, LoginResultEnum.USER_DISABLED);
createLoginLog(user.getId(), username, null, organId, logTypeEnum, LoginResultEnum.USER_DISABLED);
throw ServiceExceptionUtil.exception(ErrorCodeConstants.AUTH_LOGIN_USER_DISABLED);
}
return user;
@@ -142,12 +148,25 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Override
public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
public AuthLoginRespVO login(AuthLoginReqVO reqVO, boolean isManageEndPoint) {
// 校验验证码
validateCaptcha(reqVO);
// 使用账号密码,进行登录
AdminUserDO user = authenticate(reqVO);
Long userId = user.getId();
// 管理端只允许超管登录
boolean isSuperAdmin = securityFrameworkService.hasAnyRoles(userId, "super_admin");
user.setSuperAdmin(isSuperAdmin);
if (isSuperAdmin || SecurityFrameworkUtils.isCfOrg(user.getOrganId())) {
user.setUserType(isManageEndPoint ? UserTypeEnum.ADMIN : UserTypeEnum.MEMBER);
} else {
if (isManageEndPoint) {
throw new ServiceException(ErrorCodeConstants.AUTH_MANAGEENDPOINT_LOGIN_PERMISSION_ERROR);
}
user.setUserType(UserTypeEnum.MEMBER);
}
Long organId = user.getOrganId();
OrganizationDO organ = organService.getOrgan(organId);
@@ -173,7 +192,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
AdminUserDO user = userService.getUserUniqueByUserName(mobile);
// 校验用户是否存在
if (user == null) {
createLoginLog(null, mobile, null, LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.BAD_CREDENTIALS);
createLoginLog(null, mobile, null, null, LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.BAD_CREDENTIALS);
return false;
}
if (StringUtils.isEmpty(user.getPassword())) {
@@ -189,7 +208,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
AdminUserDO user = userService.getUserUniqueByUserName(mobile);
// 校验用户是否存在
if (user == null) {
createLoginLog(null, mobile, null, LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.BAD_CREDENTIALS);
createLoginLog(null, mobile, null, null, LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.BAD_CREDENTIALS);
return false;
}
// 校验验证码正确性
@@ -228,7 +247,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, dataSourceCode);
}
private void createLoginLog(Long userId, String username, Long organId,
private void createLoginLog(Long userId, String username, UserTypeEnum userTypeEnum, Long organId,
LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
// 手动控制事务
transactionTemplate.executeWithoutResult(status -> {
@@ -302,7 +321,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
// 验证不通过
if (!response.isSuccess()) {
// 创建登录失败日志(验证码不正确)
createLoginLog(null, reqVO.getUsername(), null, LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.CAPTCHA_CODE_ERROR);
createLoginLog(null, reqVO.getUsername(), null, null, LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.CAPTCHA_CODE_ERROR);
throw ServiceExceptionUtil.exception(ErrorCodeConstants.AUTH_LOGIN_CAPTCHA_CODE_ERROR, response.getRepMsg());
}
}
@@ -318,7 +337,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
*/
private AuthLoginRespVO createTokenAfterLoginSuccess(AdminUserDO user, String username, LoginLogTypeEnum logType, String dataCode) {
// 插入登陆日志
createLoginLog(user.getId(), username, user.getOrganId(), logType, LoginResultEnum.SUCCESS);
createLoginLog(user.getId(), username, user.getUserType(), user.getOrganId(), logType, LoginResultEnum.SUCCESS);
// 创建访问令牌
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(user, getUserType().getValue(), OAuth2ClientConstants.CLIENT_ID_DEFAULT, dataCode);
// 构建返回结果
@@ -349,11 +368,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
reqDTO.setTraceId(TracerUtils.getTraceId());
reqDTO.setUserId(userId);
reqDTO.setUserType(userType);
if (ObjectUtil.equal(getUserType().getValue(), userType)) {
reqDTO.setUsername(getUsername(userId));
} else {
reqDTO.setUsername(memberService.getMemberUserMobile(userId));
}
reqDTO.setUsername(getUsername(userId));
// 设置登录时通过ip云服务查询到的地域信息
if (ipQueryService.serviceEnable()) {
IPQueryDataRespDTO ipQueryDataRespDTO = ipQueryService.querySource(clientIP);
@@ -218,7 +218,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
Long userId = user.getId();
OAuth2AccessTokenDO refreshToken = new OAuth2AccessTokenDO()
.setUserId(userId)
.setUserType(userType)
.setUserType(user.getUserType().getValue())
.setDataCode(dataCode)
.setOrganId(organId)
.setNickname(user.getNickname())
@@ -228,8 +228,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
if (organId != null) {
OrganContextHolder.setOrganId(organId);
}
boolean b = securityFrameworkService.hasAnyRoles(userId, "super_admin");
refreshToken.setIsSupAdmin(b);
refreshToken.setIsSupAdmin(user.isSuperAdmin());
return refreshToken;
}
@@ -86,4 +86,20 @@ public interface MenuService {
List<MenuDO> getMenuList(Collection<Long> ids);
List<MenuDO> getMenuList1(Collection<Long> ids);
/**
* 查询管理端菜单列表
*
* @param ids 菜单id列表
* @return
*/
List<MenuDO> getManageEndPointMenuList(Collection<Long> ids);
/**
* 查询生产端菜单列表
*
* @param ids 菜单id列表
* @return
*/
List<MenuDO> getCustomEndPointMenuList(Collection<Long> ids);
}
@@ -2,13 +2,17 @@ package com.cf.imes.module.system.service.permission;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.organ.core.aop.OrganIgnore;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
import com.cf.imes.module.system.controller.admin.permission.vo.menu.MenuSaveVO;
import com.cf.imes.module.system.dal.dataobject.permission.MenuDO;
import com.cf.imes.module.system.dal.mysql.permission.MenuMapper;
import com.cf.imes.module.system.dal.redis.RedisKeyConstants;
import com.cf.imes.module.system.enums.permission.MenuSourceTypeEnum;
import com.cf.imes.module.system.enums.permission.MenuTypeEnum;
import com.cf.imes.module.system.service.organ.OrganService;
import com.google.common.annotations.VisibleForTesting;
@@ -64,6 +68,8 @@ public class MenuServiceImpl implements MenuService {
validateParentMenu(createReqVO.getParentId(), null);
// 校验菜单(自己)
validateMenu(createReqVO.getParentId(), createReqVO.getName(), null);
// 校验管理端菜单增删改必须是晨丰组织下用户
validateManageSourceTypeOperatePermission(createReqVO.getSourceType());
// 插入数据库
MenuDO menu = BeanUtils.toBean(createReqVO, MenuDO.class);
@@ -91,6 +97,8 @@ public class MenuServiceImpl implements MenuService {
validateParentMenu(updateReqVO.getParentId(), updateReqVO.getId());
// 校验菜单(自己)
validateMenu(updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getId());
// 校验管理端菜单增删改必须是晨丰组织下用户
validateManageSourceTypeOperatePermission(updateReqVO.getSourceType());
// 更新到数据库
MenuDO updateObj = BeanUtils.toBean(updateReqVO, MenuDO.class);
@@ -119,6 +127,8 @@ public class MenuServiceImpl implements MenuService {
if (menuDO == null) {
throw exception(MENU_NOT_EXISTS);
}
// 校验管理端菜单增删改必须是晨丰组织下用户
validateManageSourceTypeOperatePermission(menuDO.getSourceType());
// 标记删除
menuMapper.deleteById(id);
// 删除授予给角色的权限
@@ -128,6 +138,17 @@ public class MenuServiceImpl implements MenuService {
flushCacheWhenOperateMenu(id, null, menuDO.getPermission());
}
/**
* 校验管理端菜单增删改必须是晨丰组织下用户
*
* @param sourceType
*/
private void validateManageSourceTypeOperatePermission(Integer sourceType) {
if (!SecurityFrameworkUtils.isCfOrg() && sourceType.equals(MenuSourceTypeEnum.MANAGEMENT.getType())) {
throw new ServiceException(MANAGEMENT_MENU_OPERATION_PERMISSION_ERROR);
}
}
/**
* 菜单增删改时清理缓存
*
@@ -303,4 +324,21 @@ public class MenuServiceImpl implements MenuService {
}
}
@Override
@OrganIgnore
public List<MenuDO> getManageEndPointMenuList(Collection<Long> ids) {
return menuMapper.selectList(new LambdaQueryWrapperX<MenuDO>()
.inIfPresent(MenuDO::getId, ids)
.ne(MenuDO::getSourceType, MenuSourceTypeEnum.PRODUCTION.getType()));
}
@Override
@OrganIgnore
public List<MenuDO> getCustomEndPointMenuList(Collection<Long> ids) {
return menuMapper.selectList(new LambdaQueryWrapperX<MenuDO>()
.inIfPresent(MenuDO::getId, ids)
.and(wr -> wr.or(wrapper -> wrapper
.isNull(MenuDO::getSourceType))
.or(wrapper -> wrapper.ne(MenuDO::getSourceType, MenuSourceTypeEnum.MANAGEMENT.getType()))));
}
}
@@ -0,0 +1,33 @@
package com.cf.imes.module.system.validation.menu;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 菜单来源类型校验注解
*
* @author Gqr
* @since 2024/10/21 11:25
*/
@Target({
ElementType.PARAMETER,
ElementType.FIELD,
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {MenuSourceTypeValidator.class}
)
public @interface MenuSourceTypeValid {
String message() default "菜单类型不合法";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@@ -0,0 +1,27 @@
package com.cf.imes.module.system.validation.menu;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.module.system.enums.permission.MenuSourceTypeEnum;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
/**
* 菜单来源类型校验器
*
* @author Gqr
* @since 2024/10/21 11:26
*/
public class MenuSourceTypeValidator implements ConstraintValidator<MenuSourceTypeValid, Integer> {
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (ObjectUtil.isNull(value)) {
return true;
}
for (MenuSourceTypeEnum typeEnum : MenuSourceTypeEnum.values()) {
if (ObjectUtil.equal(typeEnum.getType(), value)) {
return true;
}
}
return false;
}
}
@@ -181,6 +181,7 @@ chenfeng:
- /admin-api/system/machine-template/*
- /admin-api/system/data-source/*
- /admin-api/system/auth/login
- /admin-api/system/auth/manage/login
- /admin-api/system/auth/logout
- /admin-api/system/auth/sms-code
- /admin-api/system/user/reset-password
@@ -58,10 +58,6 @@ spring:
name: imes_base
url: jdbc:mysql://192.168.1.205:3307/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例
# url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.master.name} # PostgreSQL 连接的示例
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=${spring.datasource.dynamic.datasource.master.name} # SQLServer 连接的示例
username: root
password: root
# username: sa
@@ -204,6 +200,7 @@ chenfeng:
- /admin-api/system/machine-template/*
- /admin-api/system/data-source/*
- /admin-api/system/auth/login
- /admin-api/system/auth/manage/login
- /admin-api/system/auth/logout
- /admin-api/system/auth/sms-code
- /admin-api/system/user/reset-password