mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 22:57:17 +08:00 
			
		
		
		
	refactor: 梳理用户和角色体系,内置角色:超级管理员、租户管理员(系统管理员),且内置用户和角色不允许变更及分配
This commit is contained in:
		| @@ -61,6 +61,15 @@ public class CrudApiPermissionPrefixCache { | ||||
|         PERMISSION_PREFIX_CACHE.clear(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取所有缓存 | ||||
|      * | ||||
|      * @return 所有缓存 | ||||
|      */ | ||||
|     public static Map<Class<?>, String> getAll() { | ||||
|         return PERMISSION_PREFIX_CACHE; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 解析权限前缀(解析路径获取模块名和资源名) | ||||
|      * | ||||
|   | ||||
| @@ -34,7 +34,7 @@ public class DefaultDataPermissionUserDataProvider implements DataPermissionUser | ||||
|  | ||||
|     @Override | ||||
|     public boolean isFilter() { | ||||
|         return !UserContextHolder.isAdmin(); | ||||
|         return !UserContextHolder.isSuperAdminUser() && !UserContextHolder.isTenantAdminUser(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -0,0 +1,50 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.admin.common.constant; | ||||
|  | ||||
| /** | ||||
|  * 全局常量 | ||||
|  * | ||||
|  * @author Charles7c | ||||
|  * @since 2023/2/9 22:11 | ||||
|  */ | ||||
| public class GlobalConstants { | ||||
|  | ||||
|     /** | ||||
|      * 根父级 ID | ||||
|      */ | ||||
|     public static final Long ROOT_PARENT_ID = 0L; | ||||
|  | ||||
|     /** | ||||
|      * 布尔值常量 | ||||
|      */ | ||||
|     public static class Boolean { | ||||
|  | ||||
|         /** | ||||
|          * 否 | ||||
|          */ | ||||
|         public static final Integer NO = 0; | ||||
|  | ||||
|         /** | ||||
|          * 是 | ||||
|          */ | ||||
|         public static final Integer YES = 1; | ||||
|     } | ||||
|  | ||||
|     private GlobalConstants() { | ||||
|     } | ||||
| } | ||||
| @@ -1,94 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.admin.common.constant; | ||||
|  | ||||
| /** | ||||
|  * 系统相关常量 | ||||
|  * | ||||
|  * @author Charles7c | ||||
|  * @since 2023/2/9 22:11 | ||||
|  */ | ||||
| public class SysConstants { | ||||
|  | ||||
|     /** | ||||
|      * 否 | ||||
|      */ | ||||
|     public static final Integer NO = 0; | ||||
|  | ||||
|     /** | ||||
|      * 是 | ||||
|      */ | ||||
|     public static final Integer YES = 1; | ||||
|  | ||||
|     /** | ||||
|      * 超管用户 ID | ||||
|      */ | ||||
|     public static final Long SUPER_USER_ID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 顶级部门 ID | ||||
|      */ | ||||
|     public static final Long SUPER_DEPT_ID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 顶级父 ID | ||||
|      */ | ||||
|     public static final Long SUPER_PARENT_ID = 0L; | ||||
|  | ||||
|     /** | ||||
|      * 超管角色编码 | ||||
|      */ | ||||
|     public static final String SUPER_ROLE_CODE = "admin"; | ||||
|  | ||||
|     /** | ||||
|      * 普通用户角色编码 | ||||
|      */ | ||||
|     public static final String GENERAL_ROLE_CODE = "general"; | ||||
|  | ||||
|     /** | ||||
|      * 超管角色 ID | ||||
|      */ | ||||
|     public static final Long SUPER_ROLE_ID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 普通用户角色 ID | ||||
|      */ | ||||
|     public static final Long GENERAL_ROLE_ID = 2L; | ||||
|  | ||||
|     /** | ||||
|      * 全部权限标识 | ||||
|      */ | ||||
|     public static final String ALL_PERMISSION = "*:*:*"; | ||||
|  | ||||
|     /** | ||||
|      * 登录 URI | ||||
|      */ | ||||
|     public static final String LOGIN_URI = "/auth/login"; | ||||
|  | ||||
|     /** | ||||
|      * 登出 URI | ||||
|      */ | ||||
|     public static final String LOGOUT_URI = "/auth/logout"; | ||||
|  | ||||
|     /** | ||||
|      * 租户管理员角色编码 | ||||
|      */ | ||||
|     public static final String TENANT_ADMIN_ROLE_CODE = "tenant_admin"; | ||||
|  | ||||
|     private SysConstants() { | ||||
|     } | ||||
| } | ||||
| @@ -17,9 +17,12 @@ | ||||
| package top.continew.admin.common.context; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.extra.spring.SpringUtil; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.config.TenantExtensionProperties; | ||||
| import top.continew.admin.common.constant.GlobalConstants; | ||||
| import top.continew.admin.common.enums.RoleCodeEnum; | ||||
| import top.continew.starter.core.util.CollUtils; | ||||
|  | ||||
| import java.io.Serial; | ||||
| @@ -101,23 +104,16 @@ public class UserContext implements Serializable { | ||||
|         this.passwordExpirationDays = passwordExpirationDays; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 设置角色 | ||||
|      * | ||||
|      * @param roles 角色 | ||||
|      */ | ||||
|     public void setRoles(Set<RoleContext> roles) { | ||||
|         this.roles = roles; | ||||
|         this.roleCodes = CollUtils.mapToSet(roles, RoleContext::getCode); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 是否为管理员 | ||||
|      * | ||||
|      * @return true:是;false:否 | ||||
|      */ | ||||
|     public boolean isAdmin() { | ||||
|         if (CollUtil.isEmpty(roleCodes)) { | ||||
|             return false; | ||||
|         } | ||||
|         return roleCodes.contains(SysConstants.SUPER_ROLE_CODE); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 密码是否已过期 | ||||
|      * | ||||
| @@ -125,7 +121,7 @@ public class UserContext implements Serializable { | ||||
|      */ | ||||
|     public boolean isPasswordExpired() { | ||||
|         // 永久有效 | ||||
|         if (this.passwordExpirationDays == null || this.passwordExpirationDays <= SysConstants.NO) { | ||||
|         if (this.passwordExpirationDays == null || this.passwordExpirationDays <= GlobalConstants.Boolean.NO) { | ||||
|             return false; | ||||
|         } | ||||
|         // 初始密码(第三方登录用户)暂不提示修改 | ||||
| @@ -134,4 +130,29 @@ public class UserContext implements Serializable { | ||||
|         } | ||||
|         return this.pwdResetTime.plusDays(this.passwordExpirationDays).isBefore(LocalDateTime.now()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 是否为超级管理员用户 | ||||
|      * | ||||
|      * @return true:是;false:否 | ||||
|      */ | ||||
|     public boolean isSuperAdminUser() { | ||||
|         if (CollUtil.isEmpty(roleCodes)) { | ||||
|             return false; | ||||
|         } | ||||
|         return roleCodes.contains(RoleCodeEnum.SUPER_ADMIN.getCode()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 是否为租户管理员用户 | ||||
|      * | ||||
|      * @return true:是;false:否 | ||||
|      */ | ||||
|     public boolean isTenantAdminUser() { | ||||
|         if (CollUtil.isEmpty(roleCodes)) { | ||||
|             return false; | ||||
|         } | ||||
|         TenantExtensionProperties tenantExtensionProperties = SpringUtil.getBean(TenantExtensionProperties.class); | ||||
|         return !tenantExtensionProperties.isDefaultTenant() && roleCodes.contains(RoleCodeEnum.TENANT_ADMIN.getCode()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -181,12 +181,22 @@ public class UserContextHolder { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 是否为管理员 | ||||
|      * 是否为超级管理员用户 | ||||
|      * | ||||
|      * @return 是否为管理员 | ||||
|      * @return true:是;false:否 | ||||
|      */ | ||||
|     public static boolean isAdmin() { | ||||
|     public static boolean isSuperAdminUser() { | ||||
|         StpUtil.checkLogin(); | ||||
|         return getContext().isAdmin(); | ||||
|         return getContext().isSuperAdminUser(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 是否为租户管理员用户 | ||||
|      * | ||||
|      * @return true:是;false:否 | ||||
|      */ | ||||
|     public static boolean isTenantAdminUser() { | ||||
|         StpUtil.checkLogin(); | ||||
|         return getContext().isTenantAdminUser(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,82 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.admin.common.enums; | ||||
|  | ||||
| import cn.hutool.extra.spring.SpringUtil; | ||||
| import lombok.Getter; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import top.continew.admin.common.config.TenantExtensionProperties; | ||||
| import top.continew.starter.extension.tenant.context.TenantContextHolder; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 角色编码枚举 | ||||
|  * | ||||
|  * @author Charles7c | ||||
|  * @since 2025/7/26 19:18 | ||||
|  */ | ||||
| @Getter | ||||
| @RequiredArgsConstructor | ||||
| public enum RoleCodeEnum { | ||||
|  | ||||
|     /** | ||||
|      * 超级管理员(内置且仅有一位超级管理员) | ||||
|      */ | ||||
|     SUPER_ADMIN("super_admin", "超级管理员"), | ||||
|  | ||||
|     /** | ||||
|      * 租户管理员 | ||||
|      */ | ||||
|     TENANT_ADMIN("admin", "系统管理员"), | ||||
|  | ||||
|     /** | ||||
|      * 系统管理员 | ||||
|      */ | ||||
|     SYSTEM_ADMIN("sys_admin", "系统管理员"), | ||||
|  | ||||
|     /** | ||||
|      * 普通用户 | ||||
|      */ | ||||
|     GENERAL_USER("general", "普通用户"); | ||||
|  | ||||
|     private final String code; | ||||
|     private final String description; | ||||
|  | ||||
|     /** | ||||
|      * 获取超级管理员角色编码列表 | ||||
|      * | ||||
|      * @return 超级管理员角色编码列表 | ||||
|      */ | ||||
|     public static List<String> getSuperRoleCodes() { | ||||
|         if (TenantContextHolder.isTenantDisabled() || SpringUtil.getBean(TenantExtensionProperties.class) | ||||
|             .isDefaultTenant()) { | ||||
|             return List.of(SUPER_ADMIN.getCode()); | ||||
|         } | ||||
|         return List.of(SUPER_ADMIN.getCode(), TENANT_ADMIN.getCode()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 判断是否为超级管理员角色编码 | ||||
|      * | ||||
|      * @param code 角色编码 | ||||
|      * @return 是否为超级管理员角色编码 | ||||
|      */ | ||||
|     public static boolean isSuperRoleCode(String code) { | ||||
|         return getSuperRoleCodes().contains(code); | ||||
|     } | ||||
| } | ||||
| @@ -30,8 +30,8 @@ import top.continew.admin.common.api.tenant.TenantDataApi; | ||||
| import top.continew.admin.common.base.service.BaseServiceImpl; | ||||
| import top.continew.admin.common.config.TenantExtensionProperties; | ||||
| import top.continew.admin.common.constant.CacheConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.common.enums.RoleCodeEnum; | ||||
| import top.continew.admin.common.model.dto.TenantDTO; | ||||
| import top.continew.admin.tenant.constant.TenantCacheConstants; | ||||
| import top.continew.admin.tenant.constant.TenantConstants; | ||||
| @@ -170,7 +170,7 @@ public class TenantServiceImpl extends BaseServiceImpl<TenantMapper, TenantDO, T | ||||
|         })); | ||||
|         // 租户管理员:新增菜单 | ||||
|         tenantIdList.forEach(tenantId -> TenantUtils.execute(tenantId, () -> { | ||||
|             Long roleId = roleApi.getIdByCode(SysConstants.TENANT_ADMIN_ROLE_CODE); | ||||
|             Long roleId = roleApi.getIdByCode(RoleCodeEnum.TENANT_ADMIN.getCode()); | ||||
|             List<Long> oldMenuIdList = roleMenuApi.listMenuIdByRoleIds(List.of(roleId)); | ||||
|             Collection<Long> addMenuIdList = CollUtil.disjunction(newMenuIds, oldMenuIdList); | ||||
|             if (CollUtil.isNotEmpty(addMenuIdList)) { | ||||
|   | ||||
| @@ -29,12 +29,12 @@ import cn.hutool.json.JSONUtil; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.http.HttpHeaders; | ||||
| import org.springframework.scheduling.annotation.Async; | ||||
| import top.continew.admin.auth.constant.AuthConstants; | ||||
| import top.continew.admin.auth.enums.AuthTypeEnum; | ||||
| import top.continew.admin.auth.model.req.AccountLoginReq; | ||||
| import top.continew.admin.auth.model.req.EmailLoginReq; | ||||
| import top.continew.admin.auth.model.req.LoginReq; | ||||
| import top.continew.admin.auth.model.req.PhoneLoginReq; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.system.enums.LogStatusEnum; | ||||
| import top.continew.admin.system.mapper.LogMapper; | ||||
| import top.continew.admin.system.model.entity.LogDO; | ||||
| @@ -92,7 +92,8 @@ public class LogDaoLocalImpl implements LogDao { | ||||
|         // 保存记录 | ||||
|         if (TenantContextHolder.isTenantEnabled()) { | ||||
|             // 异步无法获取租户 ID | ||||
|             String tenantId = logRequest.getHeaders().get(SpringUtil.getBean(TenantProperties.class).getTenantIdHeader()); | ||||
|             String tenantId = logRequest.getHeaders() | ||||
|                 .get(SpringUtil.getBean(TenantProperties.class).getTenantIdHeader()); | ||||
|             if (StrUtil.isNotBlank(tenantId)) { | ||||
|                 TenantUtils.execute(Long.parseLong(tenantId), () -> logMapper.insert(logDO)); | ||||
|                 return; | ||||
| @@ -154,13 +155,13 @@ public class LogDaoLocalImpl implements LogDao { | ||||
|         String requestUri = URLUtil.getPath(logDO.getRequestUrl()); | ||||
|         // 解析退出接口信息 | ||||
|         String responseBody = logResponse.getBody(); | ||||
|         if (requestUri.startsWith(SysConstants.LOGOUT_URI) && StrUtil.isNotBlank(responseBody)) { | ||||
|         if (requestUri.startsWith(AuthConstants.LOGOUT_URI) && StrUtil.isNotBlank(responseBody)) { | ||||
|             R result = JSONUtil.toBean(responseBody, R.class); | ||||
|             logDO.setCreateUser(Convert.toLong(result.getData(), null)); | ||||
|             return; | ||||
|         } | ||||
|         // 解析登录接口信息 | ||||
|         if (requestUri.startsWith(SysConstants.LOGIN_URI) && LogStatusEnum.SUCCESS.equals(logDO.getStatus())) { | ||||
|         if (requestUri.startsWith(AuthConstants.LOGIN_URI) && LogStatusEnum.SUCCESS.equals(logDO.getStatus())) { | ||||
|             String requestBody = logRequest.getBody(); | ||||
|             logDO.setDescription(JSONUtil.toBean(requestBody, LoginReq.class).getAuthType().getDescription() + "登录"); | ||||
|             // 解析账号登录用户为操作人 | ||||
|   | ||||
| @@ -27,6 +27,7 @@ import cn.dev33.satoken.sign.template.SaSignUtil; | ||||
| import cn.dev33.satoken.stp.StpInterface; | ||||
| import cn.dev33.satoken.stp.StpUtil; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.aop.framework.AopProxyUtils; | ||||
| import org.springframework.aop.support.AopUtils; | ||||
| import org.springframework.boot.context.event.ApplicationReadyEvent; | ||||
| @@ -54,6 +55,7 @@ import java.util.*; | ||||
|  * @author chengzi | ||||
|  * @since 2022/12/19 22:13 | ||||
|  */ | ||||
| @Slf4j | ||||
| @Configuration | ||||
| @RequiredArgsConstructor | ||||
| public class SaTokenConfiguration { | ||||
| @@ -133,5 +135,6 @@ public class SaTokenConfiguration { | ||||
|             // 转回数组 | ||||
|             properties.getSecurity().setExcludes(allExcludes.toArray(new String[0])); | ||||
|         } | ||||
|         log.debug("缓存 CRUD API 权限前缀完成:{}", CrudApiPermissionPrefixCache.getAll().values()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -46,7 +46,7 @@ import org.springframework.web.bind.annotation.*; | ||||
| import top.continew.admin.auth.model.resp.CaptchaResp; | ||||
| import top.continew.admin.common.config.CaptchaProperties; | ||||
| import top.continew.admin.common.constant.CacheConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.constant.GlobalConstants; | ||||
| import top.continew.admin.system.enums.OptionCategoryEnum; | ||||
| import top.continew.admin.system.model.entity.SmsConfigDO; | ||||
| import top.continew.admin.system.service.OptionService; | ||||
| @@ -119,7 +119,7 @@ public class CaptchaController { | ||||
|     @GetMapping("/image") | ||||
|     public CaptchaResp getImageCaptcha() { | ||||
|         int loginCaptchaEnabled = optionService.getValueByCode2Int("LOGIN_CAPTCHA_ENABLED"); | ||||
|         if (SysConstants.NO.equals(loginCaptchaEnabled)) { | ||||
|         if (GlobalConstants.Boolean.NO.equals(loginCaptchaEnabled)) { | ||||
|             return CaptchaResp.builder().isEnabled(false).build(); | ||||
|         } | ||||
|         String uuid = IdUtil.fastUUID(); | ||||
|   | ||||
| @@ -77,10 +77,8 @@ public class DemoEnvironmentJob { | ||||
|     private static final Long DELETE_FLAG = 10000L; | ||||
|     private static final Long MESSAGE_FLAG = 0L; | ||||
|     private static final List<Long> USER_FLAG = List | ||||
|         .of(1L, 547889293968801822L, 547889293968801823L, 547889293968801824L, 547889293968801825L, | ||||
|                 547889293968801826L, 547889293968801827L, 547889293968801828L, 547889293968801829L, | ||||
|                 547889293968801830L, 547889293968801831L, 547889293968801832L, 547889293968801833L, 547889293968801834L); | ||||
|     private static final List<Long> ROLE_FLAG = List.of(1L, 2L, 547888897925840927L, 547888897925840928L); | ||||
|         .of(1L, 547889293968801822L, 547889293968801823L, 547889293968801824L, 547889293968801825L, 547889293968801826L, 547889293968801827L, 547889293968801828L, 547889293968801829L, 547889293968801830L, 547889293968801831L, 547889293968801832L, 547889293968801833L, 547889293968801834L); | ||||
|     private static final List<Long> ROLE_FLAG = List.of(1L, 2L, 3L, 547888897925840927L, 547888897925840928L); | ||||
|     private static final Long DEPT_FLAG = 547887852587843611L; | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -206,7 +206,7 @@ continew-starter.tenant: | ||||
|   tenant-id-header: X-Tenant-Id | ||||
|   # 请求头中租户编码键名 | ||||
|   tenant-code-header: X-Tenant-Code | ||||
|   # 默认租户 ID:超管用户所在租户(默认:0) | ||||
|   # 默认租户 ID:超级管理员用户所在租户(默认:0) | ||||
|   default-tenant-id: 0 | ||||
|   # 忽略表(忽略拼接租户条件) | ||||
|   ignore-tables: | ||||
|   | ||||
| @@ -164,8 +164,9 @@ VALUES | ||||
| INSERT INTO `sys_role` | ||||
| (`id`, `name`, `code`, `data_scope`, `description`, `sort`, `is_system`, `create_user`, `create_time`) | ||||
| VALUES | ||||
| (1, '系统管理员', 'admin', 1, '系统初始角色', 1, b'1', 1, NOW()), | ||||
| (2, '普通用户', 'general', 4, '系统初始角色', 2, b'1', 1, NOW()), | ||||
| (1, '超级管理员', 'super_admin', 1, '系统初始角色', 0, b'1', 1, NOW()), | ||||
| (2, '系统管理员', 'sys_admin', 1, NULL, 1, b'0', 1, NOW()), | ||||
| (3, '普通用户', 'general', 4, NULL, 2, b'0', 1, NOW()), | ||||
| (547888897925840927, '测试人员', 'tester', 5, NULL, 3, b'0', 1, NOW()), | ||||
| (547888897925840928, '研发人员', 'developer', 4, NULL, 4, b'0', 1, NOW()); | ||||
|  | ||||
| @@ -173,7 +174,7 @@ VALUES | ||||
| INSERT INTO `sys_user` | ||||
| (`id`, `username`, `nickname`, `password`, `gender`, `email`, `phone`, `avatar`, `description`, `status`, `is_system`, `pwd_reset_time`, `dept_id`, `create_user`, `create_time`) | ||||
| VALUES | ||||
| (1, 'admin', '系统管理员', '{bcrypt}$2a$10$4jGwK2BMJ7FgVR.mgwGodey8.xR8FLoU1XSXpxJ9nZQt.pufhasSa', 1, '42190c6c5639d2ca4edb4150a35e058559ccf8270361a23745a2fd285a273c28', '5bda89a4609a65546422ea56bfe5eab4', NULL, '系统初始用户', 1, b'1', NOW(), 1, 1, NOW()), | ||||
| (1, 'admin', '超级管理员', '{bcrypt}$2a$10$4jGwK2BMJ7FgVR.mgwGodey8.xR8FLoU1XSXpxJ9nZQt.pufhasSa', 1, '42190c6c5639d2ca4edb4150a35e058559ccf8270361a23745a2fd285a273c28', '5bda89a4609a65546422ea56bfe5eab4', NULL, '系统初始用户', 1, b'1', NOW(), 1, 1, NOW()), | ||||
| (547889293968801822, 'test', '测试员', '{bcrypt}$2a$10$xAsoeMJ.jc/kSxhviLAg7.j2iFrhi6yYAdniNdjLiIUWU/BRZl2Ti', 2, NULL, NULL, NULL, NULL, 1, b'0', NOW(), 547887852587843593, 1, NOW()), | ||||
| (547889293968801823, 'Charles', 'Charles', '{bcrypt}$2a$10$xAsoeMJ.jc/kSxhviLAg7.j2iFrhi6yYAdniNdjLiIUWU/BRZl2Ti', 1, NULL, NULL, NULL, '代码写到极致,就是艺术。', 1, b'0', NOW(), 547887852587843595, 1, NOW()), | ||||
| (547889293968801824, 'Yoofff', 'Yoofff', '{bcrypt}$2a$10$xAsoeMJ.jc/kSxhviLAg7.j2iFrhi6yYAdniNdjLiIUWU/BRZl2Ti', 1, NULL, NULL, NULL, '弱小和无知不是生存的障碍,傲慢才是。', 2, b'0', NOW(), 1, 1, NOW()), | ||||
|   | ||||
| @@ -164,8 +164,9 @@ VALUES | ||||
| INSERT INTO "sys_role" | ||||
| ("id", "name", "code", "data_scope", "description", "sort", "is_system", "create_user", "create_time") | ||||
| VALUES | ||||
| (1, '系统管理员', 'admin', 1, '系统初始角色', 1, true, 1, NOW()), | ||||
| (2, '普通用户', 'general', 4, '系统初始角色', 2, true, 1, NOW()), | ||||
| (1, '超级管理员', 'super_admin', 1, '系统初始角色', 0, true, 1, NOW()), | ||||
| (2, '系统管理员', 'sys_admin', 1, NULL, 1, false, 1, NOW()), | ||||
| (3, '普通用户', 'general', 4, NULL, 2, false, 1, NOW()), | ||||
| (547888897925840927, '测试人员', 'tester', 5, NULL, 3, false, 1, NOW()), | ||||
| (547888897925840928, '研发人员', 'developer', 4, NULL, 4, false, 1, NOW()); | ||||
|  | ||||
| @@ -173,7 +174,7 @@ VALUES | ||||
| INSERT INTO "sys_user" | ||||
| ("id", "username", "nickname", "password", "gender", "email", "phone", "avatar", "description", "status", "is_system", "pwd_reset_time", "dept_id", "create_user", "create_time") | ||||
| VALUES | ||||
| (1, 'admin', '系统管理员', '{bcrypt}$2a$10$4jGwK2BMJ7FgVR.mgwGodey8.xR8FLoU1XSXpxJ9nZQt.pufhasSa', 1, '42190c6c5639d2ca4edb4150a35e058559ccf8270361a23745a2fd285a273c28', '5bda89a4609a65546422ea56bfe5eab4', NULL, '系统初始用户', 1, true, NOW(), 1, 1, NOW()), | ||||
| (1, 'admin', '超级管理员', '{bcrypt}$2a$10$4jGwK2BMJ7FgVR.mgwGodey8.xR8FLoU1XSXpxJ9nZQt.pufhasSa', 1, '42190c6c5639d2ca4edb4150a35e058559ccf8270361a23745a2fd285a273c28', '5bda89a4609a65546422ea56bfe5eab4', NULL, '系统初始用户', 1, true, NOW(), 1, 1, NOW()), | ||||
| (547889293968801822, 'test', '测试员', '{bcrypt}$2a$10$xAsoeMJ.jc/kSxhviLAg7.j2iFrhi6yYAdniNdjLiIUWU/BRZl2Ti', 2, NULL, NULL, NULL, NULL, 1, false, NOW(), 547887852587843593, 1, NOW()), | ||||
| (547889293968801823, 'Charles', 'Charles', '{bcrypt}$2a$10$xAsoeMJ.jc/kSxhviLAg7.j2iFrhi6yYAdniNdjLiIUWU/BRZl2Ti', 1, NULL, NULL, NULL, '代码写到极致,就是艺术。', 1, false, NOW(), 547887852587843595, 1, NOW()), | ||||
| (547889293968801824, 'Yoofff', 'Yoofff', '{bcrypt}$2a$10$xAsoeMJ.jc/kSxhviLAg7.j2iFrhi6yYAdniNdjLiIUWU/BRZl2Ti', 1, NULL, NULL, NULL, '弱小和无知不是生存的障碍,傲慢才是。', 1, false, NOW(), 1, 1, NOW()), | ||||
|   | ||||
| @@ -0,0 +1,39 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.admin.auth.constant; | ||||
|  | ||||
| /** | ||||
|  * 认证相关常量 | ||||
|  * | ||||
|  * @author Charles7c | ||||
|  * @since 2025/7/26 12:05 | ||||
|  */ | ||||
| public class AuthConstants { | ||||
|  | ||||
|     /** | ||||
|      * 登录 URI | ||||
|      */ | ||||
|     public static final String LOGIN_URI = "/auth/login"; | ||||
|  | ||||
|     /** | ||||
|      * 登出 URI | ||||
|      */ | ||||
|     public static final String LOGOUT_URI = "/auth/logout"; | ||||
|  | ||||
|     private AuthConstants() { | ||||
|     } | ||||
| } | ||||
| @@ -30,7 +30,7 @@ import top.continew.admin.auth.enums.AuthTypeEnum; | ||||
| import top.continew.admin.auth.model.req.AccountLoginReq; | ||||
| import top.continew.admin.auth.model.resp.LoginResp; | ||||
| import top.continew.admin.common.constant.CacheConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.constant.GlobalConstants; | ||||
| import top.continew.admin.common.util.SecureUtils; | ||||
| import top.continew.admin.system.enums.PasswordPolicyEnum; | ||||
| import top.continew.admin.system.model.entity.user.UserDO; | ||||
| @@ -78,7 +78,7 @@ public class AccountLoginHandler extends AbstractLoginHandler<AccountLoginReq> { | ||||
|         super.preLogin(req, client, request); | ||||
|         // 校验验证码 | ||||
|         int loginCaptchaEnabled = optionService.getValueByCode2Int("LOGIN_CAPTCHA_ENABLED"); | ||||
|         if (SysConstants.YES.equals(loginCaptchaEnabled)) { | ||||
|         if (GlobalConstants.Boolean.YES.equals(loginCaptchaEnabled)) { | ||||
|             ValidationUtils.throwIfBlank(req.getCaptcha(), "验证码不能为空"); | ||||
|             ValidationUtils.throwIfBlank(req.getUuid(), "验证码标识不能为空"); | ||||
|             String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + req.getUuid(); | ||||
| @@ -104,7 +104,7 @@ public class AccountLoginHandler extends AbstractLoginHandler<AccountLoginReq> { | ||||
|     private void checkUserLocked(String username, HttpServletRequest request, boolean isError) { | ||||
|         // 不锁定 | ||||
|         int maxErrorCount = optionService.getValueByCode2Int(PasswordPolicyEnum.PASSWORD_ERROR_LOCK_COUNT.name()); | ||||
|         if (maxErrorCount <= SysConstants.NO) { | ||||
|         if (maxErrorCount <= GlobalConstants.Boolean.NO) { | ||||
|             return; | ||||
|         } | ||||
|         // 检测是否已被锁定 | ||||
|   | ||||
| @@ -38,9 +38,10 @@ import top.continew.admin.auth.enums.AuthTypeEnum; | ||||
| import top.continew.admin.auth.model.req.SocialLoginReq; | ||||
| import top.continew.admin.auth.model.resp.LoginResp; | ||||
| import top.continew.admin.common.constant.RegexConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.common.enums.GenderEnum; | ||||
| import top.continew.admin.common.enums.RoleCodeEnum; | ||||
| import top.continew.admin.system.constant.SystemConstants; | ||||
| import top.continew.admin.system.enums.MessageTemplateEnum; | ||||
| import top.continew.admin.system.enums.MessageTypeEnum; | ||||
| import top.continew.admin.system.model.entity.user.UserDO; | ||||
| @@ -107,11 +108,12 @@ public class SocialLoginHandler extends AbstractLoginHandler<SocialLoginReq> { | ||||
|                 user.setGender(GenderEnum.valueOf(authUser.getGender().name())); | ||||
|             } | ||||
|             user.setAvatar(authUser.getAvatar()); | ||||
|             user.setDeptId(SysConstants.SUPER_DEPT_ID); | ||||
|             user.setDeptId(SystemConstants.SUPER_DEPT_ID); | ||||
|             user.setStatus(DisEnableStatusEnum.ENABLE); | ||||
|             userService.save(user); | ||||
|             Long userId = user.getId(); | ||||
|             userRoleService.assignRolesToUser(Collections.singletonList(SysConstants.GENERAL_ROLE_ID), userId); | ||||
|             userRoleService.assignRolesToUser(Collections.singletonList(roleService | ||||
|                 .getIdByCode(RoleCodeEnum.GENERAL_USER.getCode())), userId); | ||||
|             userSocial = new UserSocialDO(); | ||||
|             userSocial.setUserId(userId); | ||||
|             userSocial.setSource(source); | ||||
|   | ||||
| @@ -31,9 +31,9 @@ import top.continew.admin.auth.model.req.LoginReq; | ||||
| import top.continew.admin.auth.model.resp.LoginResp; | ||||
| import top.continew.admin.auth.model.resp.RouteResp; | ||||
| import top.continew.admin.auth.service.AuthService; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.context.RoleContext; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.system.constant.SystemConstants; | ||||
| import top.continew.admin.system.enums.MenuTypeEnum; | ||||
| import top.continew.admin.system.model.resp.ClientResp; | ||||
| import top.continew.admin.system.model.resp.MenuResp; | ||||
| @@ -93,8 +93,8 @@ public class AuthServiceImpl implements AuthService { | ||||
|         } | ||||
|         // 查询菜单列表 | ||||
|         Set<MenuResp> menuSet = new LinkedHashSet<>(); | ||||
|         if (roleSet.stream().anyMatch(r -> SysConstants.SUPER_ROLE_ID.equals(r.getId()))) { | ||||
|             menuSet.addAll(menuService.listByRoleId(SysConstants.SUPER_ROLE_ID)); | ||||
|         if (roleSet.stream().anyMatch(r -> SystemConstants.SUPER_ADMIN_ROLE_ID.equals(r.getId()))) { | ||||
|             menuSet.addAll(menuService.listByRoleId(SystemConstants.SUPER_ADMIN_ROLE_ID)); | ||||
|         } else { | ||||
|             roleSet.forEach(r -> menuSet.addAll(menuService.listByRoleId(r.getId()))); | ||||
|         } | ||||
|   | ||||
| @@ -19,11 +19,8 @@ package top.continew.admin.system.api; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.stereotype.Service; | ||||
| import top.continew.admin.common.api.system.RoleApi; | ||||
| import top.continew.admin.system.model.entity.RoleDO; | ||||
| import top.continew.admin.system.service.RoleService; | ||||
|  | ||||
| import java.util.Optional; | ||||
|  | ||||
| /** | ||||
|  * 角色业务 API 实现 | ||||
|  *  | ||||
| @@ -38,7 +35,7 @@ public class RoleApiImpl implements RoleApi { | ||||
|  | ||||
|     @Override | ||||
|     public Long getIdByCode(String code) { | ||||
|         return Optional.ofNullable(baseService.getByCode(code)).map(RoleDO::getId).orElse(null); | ||||
|         return baseService.getIdByCode(code); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -27,11 +27,12 @@ import org.springframework.transaction.annotation.Transactional; | ||||
| import top.continew.admin.common.api.tenant.PackageMenuApi; | ||||
| import top.continew.admin.common.api.tenant.TenantApi; | ||||
| import top.continew.admin.common.api.tenant.TenantDataApi; | ||||
| import top.continew.admin.common.constant.GlobalConstants; | ||||
| import top.continew.admin.common.constant.RegexConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.enums.DataScopeEnum; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.common.enums.GenderEnum; | ||||
| import top.continew.admin.common.enums.RoleCodeEnum; | ||||
| import top.continew.admin.common.model.dto.TenantDTO; | ||||
| import top.continew.admin.common.util.SecureUtils; | ||||
| import top.continew.admin.system.mapper.*; | ||||
| @@ -44,7 +45,7 @@ import top.continew.admin.system.model.entity.RoleDO; | ||||
| import top.continew.admin.system.model.entity.user.UserDO; | ||||
| import top.continew.admin.system.service.FileService; | ||||
| import top.continew.admin.system.service.RoleMenuService; | ||||
| import top.continew.admin.system.service.RoleService; | ||||
| import top.continew.admin.system.service.UserRoleService; | ||||
| import top.continew.starter.core.util.CollUtils; | ||||
| import top.continew.starter.core.util.ExceptionUtils; | ||||
| import top.continew.starter.core.util.validation.ValidationUtils; | ||||
| @@ -66,7 +67,7 @@ public class TenantDataApiForSystemImpl implements TenantDataApi { | ||||
|  | ||||
|     private final PackageMenuApi packageMenuApi; | ||||
|     private final TenantApi tenantApi; | ||||
|     private final RoleService roleService; | ||||
|     private final UserRoleService userRoleService; | ||||
|     private final FileService fileService; | ||||
|     private final RoleMenuService roleMenuService; | ||||
|     private final DeptMapper deptMapper; | ||||
| @@ -97,7 +98,7 @@ public class TenantDataApiForSystemImpl implements TenantDataApi { | ||||
|             // 初始化管理用户 | ||||
|             Long userId = this.initUserData(tenant, deptId); | ||||
|             // 用户绑定角色 | ||||
|             roleService.assignToUsers(roleId, ListUtil.of(userId)); | ||||
|             userRoleService.assignRoleToUsers(roleId, ListUtil.of(userId)); | ||||
|             // 租户绑定用户 | ||||
|             tenantApi.bindAdminUser(tenantId, userId); | ||||
|         }); | ||||
| @@ -146,11 +147,12 @@ public class TenantDataApiForSystemImpl implements TenantDataApi { | ||||
|     private Long initDeptData(TenantDTO tenant) { | ||||
|         DeptDO dept = new DeptDO(); | ||||
|         dept.setName(tenant.getName()); | ||||
|         dept.setParentId(SysConstants.SUPER_PARENT_ID); | ||||
|         dept.setAncestors("0"); | ||||
|         dept.setParentId(GlobalConstants.ROOT_PARENT_ID); | ||||
|         dept.setAncestors(GlobalConstants.ROOT_PARENT_ID.toString()); | ||||
|         dept.setDescription("系统初始部门"); | ||||
|         dept.setSort(1); | ||||
|         dept.setStatus(DisEnableStatusEnum.ENABLE); | ||||
|         dept.setIsSystem(true); | ||||
|         deptMapper.insert(dept); | ||||
|         return dept.getId(); | ||||
|     } | ||||
| @@ -163,8 +165,9 @@ public class TenantDataApiForSystemImpl implements TenantDataApi { | ||||
|      */ | ||||
|     private Long initRoleData(TenantDTO tenant) { | ||||
|         RoleDO role = new RoleDO(); | ||||
|         role.setName("系统管理员"); | ||||
|         role.setCode(SysConstants.TENANT_ADMIN_ROLE_CODE); | ||||
|         RoleCodeEnum tenantAdmin = RoleCodeEnum.TENANT_ADMIN; | ||||
|         role.setName(tenantAdmin.getDescription()); | ||||
|         role.setCode(tenantAdmin.getCode()); | ||||
|         role.setDataScope(DataScopeEnum.ALL); | ||||
|         role.setDescription("系统初始角色"); | ||||
|         role.setSort(1); | ||||
| @@ -191,7 +194,7 @@ public class TenantDataApiForSystemImpl implements TenantDataApi { | ||||
|         // 初始化用户 | ||||
|         UserDO user = new UserDO(); | ||||
|         user.setUsername(tenant.getUsername()); | ||||
|         user.setNickname("系统管理员"); | ||||
|         user.setNickname(RoleCodeEnum.TENANT_ADMIN.getDescription()); | ||||
|         user.setPassword(rawPassword); | ||||
|         user.setGender(GenderEnum.UNKNOWN); | ||||
|         user.setDescription("系统初始用户"); | ||||
|   | ||||
| @@ -20,7 +20,7 @@ import cn.hutool.core.map.MapUtil; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.stereotype.Component; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.constant.GlobalConstants; | ||||
| import top.continew.admin.system.enums.OptionCategoryEnum; | ||||
| import top.continew.admin.system.service.OptionService; | ||||
| import top.continew.starter.messaging.mail.core.MailConfig; | ||||
| @@ -52,7 +52,7 @@ public class MailConfigurerImpl implements MailConfigurer { | ||||
|         mailConfig.setPort(MapUtil.getInt(map, "MAIL_PORT")); | ||||
|         mailConfig.setUsername(MapUtil.getStr(map, "MAIL_USERNAME")); | ||||
|         mailConfig.setPassword(MapUtil.getStr(map, "MAIL_PASSWORD")); | ||||
|         mailConfig.setSslEnabled(SysConstants.YES.equals(MapUtil.getInt(map, "MAIL_SSL_ENABLED"))); | ||||
|         mailConfig.setSslEnabled(GlobalConstants.Boolean.YES.equals(MapUtil.getInt(map, "MAIL_SSL_ENABLED"))); | ||||
|         if (mailConfig.isSslEnabled()) { | ||||
|             mailConfig.setSslPort(MapUtil.getInt(map, "MAIL_SSL_PORT")); | ||||
|         } | ||||
|   | ||||
| @@ -0,0 +1,44 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.admin.system.constant; | ||||
|  | ||||
| /** | ||||
|  * 系统管理相关常量 | ||||
|  * | ||||
|  * @author Charles7c | ||||
|  * @since 2025/7/26 12:05 | ||||
|  */ | ||||
| public class SystemConstants { | ||||
|  | ||||
|     /** | ||||
|      * 超级管理员角色 ID(内置且仅有一位超级管理员用户) | ||||
|      */ | ||||
|     public static final Long SUPER_ADMIN_ROLE_ID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 顶级部门 ID | ||||
|      */ | ||||
|     public static final Long SUPER_DEPT_ID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 全部权限标识 | ||||
|      */ | ||||
|     public static final String ALL_PERMISSION = "*:*:*"; | ||||
|  | ||||
|     private SystemConstants() { | ||||
|     } | ||||
| } | ||||
| @@ -25,7 +25,7 @@ import cn.hutool.extra.spring.SpringUtil; | ||||
| import lombok.Getter; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import top.continew.admin.common.constant.RegexConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.constant.GlobalConstants; | ||||
| import top.continew.admin.system.model.entity.user.UserDO; | ||||
| import top.continew.admin.system.service.OptionService; | ||||
| import top.continew.admin.system.service.UserPasswordHistoryService; | ||||
| @@ -47,7 +47,7 @@ public enum PasswordPolicyEnum { | ||||
|     /** | ||||
|      * 密码错误锁定阈值 | ||||
|      */ | ||||
|     PASSWORD_ERROR_LOCK_COUNT("密码错误锁定阈值取值范围为 %d-%d", SysConstants.NO, 10, "由于您连续 %s 次输入错误密码,账号已被锁定 %s 分钟,预计解锁时间为 %s,请稍后再试"), | ||||
|     PASSWORD_ERROR_LOCK_COUNT("密码错误锁定阈值取值范围为 %d-%d", GlobalConstants.Boolean.NO, 10, "由于您连续 %s 次输入错误密码,账号已被锁定 %s 分钟,预计解锁时间为 %s,请稍后再试"), | ||||
|  | ||||
|     /** | ||||
|      * 账号锁定时长(分钟) | ||||
| @@ -57,12 +57,12 @@ public enum PasswordPolicyEnum { | ||||
|     /** | ||||
|      * 密码有效期(天) | ||||
|      */ | ||||
|     PASSWORD_EXPIRATION_DAYS("密码有效期取值范围为 %d-%d 天", SysConstants.NO, 999, null), | ||||
|     PASSWORD_EXPIRATION_DAYS("密码有效期取值范围为 %d-%d 天", GlobalConstants.Boolean.NO, 999, null), | ||||
|  | ||||
|     /** | ||||
|      * 密码到期提醒(天) | ||||
|      */ | ||||
|     PASSWORD_EXPIRATION_WARNING_DAYS("密码到期提醒取值范围为 %d-%d 天", SysConstants.NO, 998, null) { | ||||
|     PASSWORD_EXPIRATION_WARNING_DAYS("密码到期提醒取值范围为 %d-%d 天", GlobalConstants.Boolean.NO, 998, null) { | ||||
|         @Override | ||||
|         public void validateRange(int value, Map<String, String> policyMap) { | ||||
|             if (CollUtil.isEmpty(policyMap)) { | ||||
| @@ -72,7 +72,7 @@ public enum PasswordPolicyEnum { | ||||
|             Integer passwordExpirationDays = ObjectUtil.defaultIfNull(Convert.toInt(policyMap | ||||
|                 .get(PASSWORD_EXPIRATION_DAYS.name())), SpringUtil.getBean(OptionService.class) | ||||
|                     .getValueByCode2Int(PASSWORD_EXPIRATION_DAYS.name())); | ||||
|             if (passwordExpirationDays > SysConstants.NO) { | ||||
|             if (passwordExpirationDays > GlobalConstants.Boolean.NO) { | ||||
|                 ValidationUtils.throwIf(value >= passwordExpirationDays, "密码到期提醒时间应小于密码有效期"); | ||||
|                 return; | ||||
|             } | ||||
| @@ -98,16 +98,17 @@ public enum PasswordPolicyEnum { | ||||
|     /** | ||||
|      * 密码是否必须包含特殊字符 | ||||
|      */ | ||||
|     PASSWORD_REQUIRE_SYMBOLS("密码是否必须包含特殊字符取值只能为是(%d)或否(%d)", SysConstants.NO, SysConstants.YES, "密码必须包含特殊字符") { | ||||
|     PASSWORD_REQUIRE_SYMBOLS("密码是否必须包含特殊字符取值只能为是(%d)或否(%d)", GlobalConstants.Boolean.NO, GlobalConstants.Boolean.YES, "密码必须包含特殊字符") { | ||||
|         @Override | ||||
|         public void validateRange(int value, Map<String, String> policyMap) { | ||||
|             ValidationUtils.throwIf(value != SysConstants.YES && value != SysConstants.NO, this.getDescription() | ||||
|                 .formatted(SysConstants.YES, SysConstants.NO)); | ||||
|             ValidationUtils.throwIf(value != GlobalConstants.Boolean.YES && value != GlobalConstants.Boolean.NO, this | ||||
|                 .getDescription() | ||||
|                 .formatted(GlobalConstants.Boolean.YES, GlobalConstants.Boolean.NO)); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void validate(String password, int value, UserDO user) { | ||||
|             ValidationUtils.throwIf(value == SysConstants.YES && !ReUtil | ||||
|             ValidationUtils.throwIf(value == GlobalConstants.Boolean.YES && !ReUtil | ||||
|                 .isMatch(RegexConstants.SPECIAL_CHARACTER, password), this.getMsg()); | ||||
|         } | ||||
|     }, | ||||
| @@ -115,16 +116,17 @@ public enum PasswordPolicyEnum { | ||||
|     /** | ||||
|      * 密码是否允许包含用户名 | ||||
|      */ | ||||
|     PASSWORD_ALLOW_CONTAIN_USERNAME("密码是否允许包含用户名取值只能为是(%d)或否(%d)", SysConstants.NO, SysConstants.YES, "密码不允许包含正反序用户名") { | ||||
|     PASSWORD_ALLOW_CONTAIN_USERNAME("密码是否允许包含用户名取值只能为是(%d)或否(%d)", GlobalConstants.Boolean.NO, GlobalConstants.Boolean.YES, "密码不允许包含正反序用户名") { | ||||
|         @Override | ||||
|         public void validateRange(int value, Map<String, String> policyMap) { | ||||
|             ValidationUtils.throwIf(value != SysConstants.YES && value != SysConstants.NO, this.getDescription() | ||||
|                 .formatted(SysConstants.YES, SysConstants.NO)); | ||||
|             ValidationUtils.throwIf(value != GlobalConstants.Boolean.YES && value != GlobalConstants.Boolean.NO, this | ||||
|                 .getDescription() | ||||
|                 .formatted(GlobalConstants.Boolean.YES, GlobalConstants.Boolean.NO)); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void validate(String password, int value, UserDO user) { | ||||
|             if (value <= SysConstants.NO) { | ||||
|             if (value <= GlobalConstants.Boolean.NO) { | ||||
|                 String username = user.getUsername(); | ||||
|                 ValidationUtils.throwIf(StrUtil.containsAnyIgnoreCase(password, username, StrUtil | ||||
|                     .reverse(username)), this.getMsg()); | ||||
|   | ||||
| @@ -20,7 +20,7 @@ import com.baomidou.mybatisplus.annotation.FieldStrategy; | ||||
| import com.baomidou.mybatisplus.annotation.TableField; | ||||
| import com.baomidou.mybatisplus.annotation.TableName; | ||||
| import lombok.Data; | ||||
| import top.continew.admin.common.base.model.entity.TenantBaseDO; | ||||
| import top.continew.admin.common.base.model.entity.BaseDO; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.common.enums.GenderEnum; | ||||
| import top.continew.starter.extension.crud.annotation.DictModel; | ||||
| @@ -39,7 +39,7 @@ import java.time.LocalDateTime; | ||||
| @Data | ||||
| @DictModel(labelKey = "nickname", extraKeys = {"username"}) | ||||
| @TableName("sys_user") | ||||
| public class UserDO extends TenantBaseDO { | ||||
| public class UserDO extends BaseDO { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|   | ||||
| @@ -61,7 +61,7 @@ public class MenuQuery implements Serializable { | ||||
|     /** | ||||
|      * 排除的菜单 ID 列表 | ||||
|      */ | ||||
|     @Schema(hidden = true, description = "菜单 ID 列表", example = "[9000]") | ||||
|     @Schema(hidden = true, description = "排除的菜单 ID 列表", example = "[9000]") | ||||
|     @Query(columns = "id", type = QueryType.NOT_IN) | ||||
|     private List<Long> excludeMenuIdList; | ||||
| } | ||||
|   | ||||
| @@ -23,6 +23,7 @@ import top.continew.starter.data.enums.QueryType; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 角色查询条件 | ||||
| @@ -43,4 +44,11 @@ public class RoleQuery implements Serializable { | ||||
|     @Schema(description = "关键词", example = "测试人员") | ||||
|     @Query(columns = {"name", "code", "description"}, type = QueryType.LIKE) | ||||
|     private String description; | ||||
|  | ||||
|     /** | ||||
|      * 排除的编码列表 | ||||
|      */ | ||||
|     @Schema(description = "排除的编码列表", example = "[super_admin,tenant_admin]") | ||||
|     @Query(columns = "code", type = QueryType.NOT_IN) | ||||
|     private List<String> excludeRoleCodes; | ||||
| } | ||||
|   | ||||
| @@ -23,14 +23,12 @@ import cn.crane4j.core.executor.handler.OneToManyAssembleOperationHandler; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
| import top.continew.admin.common.constant.ContainerConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.common.enums.GenderEnum; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * 角色关联用户响应参数 | ||||
| @@ -126,6 +124,6 @@ public class RoleUserResp implements Serializable { | ||||
|     private List<String> roleNames; | ||||
|  | ||||
|     public Boolean getDisabled() { | ||||
|         return this.getIsSystem() && Objects.equals(roleId, SysConstants.SUPER_ROLE_ID); | ||||
|         return this.getIsSystem(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -85,12 +85,12 @@ public interface RoleService extends BaseService<RoleResp, RoleDetailResp, RoleQ | ||||
|     Set<RoleContext> listByUserId(Long userId); | ||||
|  | ||||
|     /** | ||||
|      * 根据角色编码查询 | ||||
|      * 根据编码查询 ID | ||||
|      * | ||||
|      * @param code 角色编码 | ||||
|      * @return 角色信息 | ||||
|      * @param code 编码 | ||||
|      * @return ID | ||||
|      */ | ||||
|     RoleDO getByCode(String code); | ||||
|     Long getIdByCode(String code); | ||||
|  | ||||
|     /** | ||||
|      * 根据角色名称查询 | ||||
|   | ||||
| @@ -28,12 +28,12 @@ import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
| import top.continew.admin.common.base.service.BaseServiceImpl; | ||||
| import top.continew.admin.common.constant.CacheConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.common.enums.RoleCodeEnum; | ||||
| import top.continew.admin.system.constant.SystemConstants; | ||||
| import top.continew.admin.system.enums.MenuTypeEnum; | ||||
| import top.continew.admin.system.mapper.MenuMapper; | ||||
| import top.continew.admin.system.model.entity.MenuDO; | ||||
| import top.continew.admin.system.model.entity.RoleDO; | ||||
| import top.continew.admin.system.model.query.MenuQuery; | ||||
| import top.continew.admin.system.model.req.MenuReq; | ||||
| import top.continew.admin.system.model.resp.MenuResp; | ||||
| @@ -113,7 +113,7 @@ public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, MenuDO, MenuRes | ||||
|     @Override | ||||
|     @Cached(key = "#roleId", name = CacheConstants.ROLE_MENU_KEY_PREFIX) | ||||
|     public List<MenuResp> listByRoleId(Long roleId) { | ||||
|         if (SysConstants.SUPER_ROLE_ID.equals(roleId)) { | ||||
|         if (SystemConstants.SUPER_ADMIN_ROLE_ID.equals(roleId)) { | ||||
|             return super.list(new MenuQuery(DisEnableStatusEnum.ENABLE), null); | ||||
|         } | ||||
|         List<MenuDO> menuList = baseMapper.selectListByRoleId(roleId); | ||||
| @@ -124,9 +124,9 @@ public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, MenuDO, MenuRes | ||||
|  | ||||
|     @Override | ||||
|     public List<Long> listExcludeTenantMenu() { | ||||
|         RoleDO role = roleService.getByCode(SysConstants.TENANT_ADMIN_ROLE_CODE); | ||||
|         Long roleId = roleService.getIdByCode(RoleCodeEnum.TENANT_ADMIN.getCode()); | ||||
|         List<Long> allMenuIdList = CollUtils.mapToList(super.list(), MenuDO::getId); | ||||
|         List<Long> menuIdList = CollUtils.mapToList(baseMapper.selectListByRoleId(role.getId()), MenuDO::getId); | ||||
|         List<Long> menuIdList = CollUtils.mapToList(baseMapper.selectListByRoleId(roleId), MenuDO::getId); | ||||
|         return CollUtil.disjunction(allMenuIdList, menuIdList).stream().toList(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -26,11 +26,12 @@ import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
| import top.continew.admin.common.base.service.BaseServiceImpl; | ||||
| import top.continew.admin.common.constant.CacheConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.context.RoleContext; | ||||
| import top.continew.admin.common.context.UserContext; | ||||
| import top.continew.admin.common.context.UserContextHolder; | ||||
| import top.continew.admin.common.enums.DataScopeEnum; | ||||
| import top.continew.admin.common.enums.RoleCodeEnum; | ||||
| import top.continew.admin.system.constant.SystemConstants; | ||||
| import top.continew.admin.system.mapper.RoleMapper; | ||||
| import top.continew.admin.system.model.entity.RoleDO; | ||||
| import top.continew.admin.system.model.query.RoleQuery; | ||||
| @@ -42,6 +43,8 @@ import top.continew.admin.system.model.resp.role.RoleResp; | ||||
| import top.continew.admin.system.service.*; | ||||
| import top.continew.starter.core.util.CollUtils; | ||||
| import top.continew.starter.core.util.validation.CheckUtils; | ||||
| import top.continew.starter.extension.crud.model.query.SortQuery; | ||||
| import top.continew.starter.extension.crud.model.resp.LabelValueResp; | ||||
|  | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| @@ -60,9 +63,10 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes | ||||
|  | ||||
|     @Resource | ||||
|     private MenuService menuService; | ||||
|     @Resource | ||||
|     private UserRoleService userRoleService; | ||||
|     private final RoleMenuService roleMenuService; | ||||
|     private final RoleDeptService roleDeptService; | ||||
|     private final UserRoleService userRoleService; | ||||
|  | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
| @@ -70,8 +74,8 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes | ||||
|         this.checkNameRepeat(req.getName(), null); | ||||
|         String code = req.getCode(); | ||||
|         this.checkCodeRepeat(code, null); | ||||
|         // 防止租户添加超管 | ||||
|         CheckUtils.throwIfEqual(SysConstants.SUPER_ROLE_CODE, code, "编码 [{}] 禁止使用", code); | ||||
|         // 防止租户添加超级管理员 | ||||
|         CheckUtils.throwIfEqual(RoleCodeEnum.SUPER_ADMIN.getCode(), code, "编码 [{}] 禁止使用", code); | ||||
|         // 新增信息 | ||||
|         Long roleId = super.create(req); | ||||
|         // 保存角色和部门关联 | ||||
| @@ -91,7 +95,7 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes | ||||
|         } | ||||
|         // 更新信息 | ||||
|         super.update(req, id); | ||||
|         if (SysConstants.SUPER_ROLE_CODE.equals(req.getCode())) { | ||||
|         if (RoleCodeEnum.isSuperRoleCode(req.getCode())) { | ||||
|             return; | ||||
|         } | ||||
|         // 保存角色和部门关联 | ||||
| @@ -129,11 +133,18 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<LabelValueResp> listDict(RoleQuery query, SortQuery sortQuery) { | ||||
|         query.setExcludeRoleCodes(RoleCodeEnum.getSuperRoleCodes()); | ||||
|         return super.listDict(query, sortQuery); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     @CacheInvalidate(key = "#id", name = CacheConstants.ROLE_MENU_KEY_PREFIX) | ||||
|     public void updatePermission(Long id, RoleUpdatePermissionReq req) { | ||||
|         super.getById(id); | ||||
|         RoleDO role = super.getById(id); | ||||
|         CheckUtils.throwIf(Boolean.TRUE.equals(role.getIsSystem()), "[{}] 是系统内置角色,不允许修改角色功能权限", role.getName()); | ||||
|         // 保存角色和菜单关联 | ||||
|         boolean isSaveMenuSuccess = roleMenuService.add(req.getMenuIds(), id); | ||||
|         // 如果功能权限有变更,则更新在线用户权限信息 | ||||
| @@ -148,7 +159,8 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes | ||||
|  | ||||
|     @Override | ||||
|     public void assignToUsers(Long id, List<Long> userIds) { | ||||
|         super.getById(id); | ||||
|         RoleDO role = super.getById(id); | ||||
|         CheckUtils.throwIf(Boolean.TRUE.equals(role.getIsSystem()), "[{}] 是系统内置角色,不允许分配角色给其他用户", role.getName()); | ||||
|         // 保存用户和角色关联 | ||||
|         userRoleService.assignRoleToUsers(id, userIds); | ||||
|         // 更新用户上下文 | ||||
| @@ -172,8 +184,8 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes | ||||
|     public Set<String> listPermissionByUserId(Long userId) { | ||||
|         Set<String> roleCodeSet = this.listCodeByUserId(userId); | ||||
|         // 超级管理员赋予全部权限 | ||||
|         if (roleCodeSet.contains(SysConstants.SUPER_ROLE_CODE)) { | ||||
|             return CollUtil.newHashSet(SysConstants.ALL_PERMISSION); | ||||
|         if (roleCodeSet.contains(RoleCodeEnum.SUPER_ADMIN.getCode())) { | ||||
|             return CollUtil.newHashSet(SystemConstants.ALL_PERMISSION); | ||||
|         } | ||||
|         return menuService.listPermissionByUserId(userId); | ||||
|     } | ||||
| @@ -202,8 +214,8 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public RoleDO getByCode(String code) { | ||||
|         return baseMapper.lambdaQuery().eq(RoleDO::getCode, code).one(); | ||||
|     public Long getIdByCode(String code) { | ||||
|         return baseMapper.lambdaQuery().eq(RoleDO::getCode, code).oneOpt().map(RoleDO::getId).orElse(null); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -22,14 +22,19 @@ import cn.hutool.core.util.StrUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||
| import com.baomidou.mybatisplus.core.metadata.IPage; | ||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
| import jakarta.annotation.Resource; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.context.annotation.Lazy; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.context.RoleContext; | ||||
| import top.continew.admin.common.enums.RoleCodeEnum; | ||||
| import top.continew.admin.system.constant.SystemConstants; | ||||
| import top.continew.admin.system.mapper.UserRoleMapper; | ||||
| import top.continew.admin.system.model.entity.UserRoleDO; | ||||
| import top.continew.admin.system.model.query.RoleUserQuery; | ||||
| import top.continew.admin.system.model.resp.role.RoleUserResp; | ||||
| import top.continew.admin.system.service.RoleService; | ||||
| import top.continew.admin.system.service.UserRoleService; | ||||
| import top.continew.starter.core.util.CollUtils; | ||||
| import top.continew.starter.core.util.validation.CheckUtils; | ||||
| @@ -38,6 +43,7 @@ import top.continew.starter.extension.crud.model.query.PageQuery; | ||||
| import top.continew.starter.extension.crud.model.resp.PageResp; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Set; | ||||
|  | ||||
| /** | ||||
|  * 用户和角色业务实现 | ||||
| @@ -50,6 +56,9 @@ import java.util.List; | ||||
| public class UserRoleServiceImpl implements UserRoleService { | ||||
|  | ||||
|     private final UserRoleMapper baseMapper; | ||||
|     @Lazy | ||||
|     @Resource | ||||
|     private RoleService roleService; | ||||
|  | ||||
|     @Override | ||||
|     @AutoOperate(type = RoleUserResp.class, on = "list") | ||||
| @@ -70,6 +79,10 @@ public class UserRoleServiceImpl implements UserRoleService { | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     public boolean assignRolesToUser(List<Long> roleIds, Long userId) { | ||||
|         // 超级管理员和租户管理员角色不允许分配 | ||||
|         CheckUtils.throwIf(roleIds.contains(SystemConstants.SUPER_ADMIN_ROLE_ID), "不允许分配超级管理员角色"); | ||||
|         Set<String> roleCodeSet = CollUtils.mapToSet(roleService.listByUserId(userId), RoleContext::getCode); | ||||
|         CheckUtils.throwIf(roleCodeSet.contains(RoleCodeEnum.TENANT_ADMIN.getCode()), "不允许分配系统管理员角色"); | ||||
|         // 检查是否有变更 | ||||
|         List<Long> oldRoleIdList = baseMapper.lambdaQuery() | ||||
|             .select(UserRoleDO::getRoleId) | ||||
| @@ -81,8 +94,6 @@ public class UserRoleServiceImpl implements UserRoleService { | ||||
|         if (CollUtil.isEmpty(CollUtil.disjunction(roleIds, oldRoleIdList))) { | ||||
|             return false; | ||||
|         } | ||||
|         CheckUtils.throwIf(SysConstants.SUPER_USER_ID.equals(userId) && !roleIds | ||||
|             .contains(SysConstants.SUPER_ROLE_ID), "不允许变更超管用户角色"); | ||||
|         // 删除原有关联 | ||||
|         baseMapper.lambdaUpdate().eq(UserRoleDO::getUserId, userId).remove(); | ||||
|         // 保存最新关联 | ||||
|   | ||||
| @@ -55,11 +55,11 @@ import org.springframework.web.multipart.MultipartFile; | ||||
| import top.continew.admin.auth.service.OnlineUserService; | ||||
| import top.continew.admin.common.base.service.BaseServiceImpl; | ||||
| import top.continew.admin.common.constant.CacheConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.common.context.UserContext; | ||||
| import top.continew.admin.common.context.UserContextHolder; | ||||
| import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.common.enums.GenderEnum; | ||||
| import top.continew.admin.system.constant.SystemConstants; | ||||
| import top.continew.admin.system.enums.OptionCategoryEnum; | ||||
| import top.continew.admin.system.mapper.user.UserMapper; | ||||
| import top.continew.admin.system.model.entity.DeptDO; | ||||
| @@ -510,7 +510,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes | ||||
|             .eq(status != null, "t1.status", status) | ||||
|             .between(CollUtil.isNotEmpty(createTimeList), "t1.create_time", CollUtil.getFirst(createTimeList), CollUtil | ||||
|                 .getLast(createTimeList)) | ||||
|             .and(deptId != null && !SysConstants.SUPER_DEPT_ID.equals(deptId), q -> { | ||||
|             .and(deptId != null && !SystemConstants.SUPER_DEPT_ID.equals(deptId), q -> { | ||||
|                 List<Long> deptIdList = CollUtils.mapToList(deptService.listChildren(deptId), DeptDO::getId); | ||||
|                 deptIdList.add(deptId); | ||||
|                 q.in("t1.dept_id", deptIdList); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user