mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 00:57:13 +08:00 
			
		
		
		
	feat: 新增密码策略-密码重复使用规则
This commit is contained in:
		| @@ -0,0 +1,38 @@ | |||||||
|  | /* | ||||||
|  |  * 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.mapper; | ||||||
|  |  | ||||||
|  | import org.apache.ibatis.annotations.Param; | ||||||
|  | import top.continew.starter.data.mybatis.plus.base.BaseMapper; | ||||||
|  | import top.continew.admin.system.model.entity.UserPasswordHistoryDO; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 用户历史密码 Mapper | ||||||
|  |  * | ||||||
|  |  * @author Charles7c | ||||||
|  |  * @since 2024/5/16 21:58 | ||||||
|  |  */ | ||||||
|  | public interface UserPasswordHistoryMapper extends BaseMapper<UserPasswordHistoryDO> { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 删除过期历史密码 | ||||||
|  |      * | ||||||
|  |      * @param userId 用户 ID | ||||||
|  |      * @param count  保留 N 个历史 | ||||||
|  |      */ | ||||||
|  |     void deleteExpired(@Param("userId") Long userId, @Param("count") int count); | ||||||
|  | } | ||||||
| @@ -17,8 +17,6 @@ | |||||||
| package top.continew.admin.system.model.entity; | package top.continew.admin.system.model.entity; | ||||||
|  |  | ||||||
| import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||||
| import com.baomidou.mybatisplus.annotation.IdType; |  | ||||||
| import com.baomidou.mybatisplus.annotation.TableId; |  | ||||||
| import com.baomidou.mybatisplus.annotation.TableName; | import com.baomidou.mybatisplus.annotation.TableName; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import org.dromara.x.file.storage.core.FileInfo; | import org.dromara.x.file.storage.core.FileInfo; | ||||||
| @@ -43,9 +41,6 @@ public class FileDO extends BaseDO { | |||||||
|     @Serial |     @Serial | ||||||
|     private static final long serialVersionUID = 1L; |     private static final long serialVersionUID = 1L; | ||||||
|  |  | ||||||
|     @TableId(type = IdType.ASSIGN_ID) |  | ||||||
|     private Long id; |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 名称 |      * 名称 | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -0,0 +1,67 @@ | |||||||
|  | /* | ||||||
|  |  * 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.model.entity; | ||||||
|  |  | ||||||
|  | import com.baomidou.mybatisplus.annotation.*; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  |  | ||||||
|  | import java.io.Serial; | ||||||
|  | import java.io.Serializable; | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 用户历史密码实体 | ||||||
|  |  * | ||||||
|  |  * @author Charles7c | ||||||
|  |  * @since 2024/5/16 21:58 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | @TableName("sys_user_password_history") | ||||||
|  | public class UserPasswordHistoryDO implements Serializable { | ||||||
|  |  | ||||||
|  |     @Serial | ||||||
|  |     private static final long serialVersionUID = 1L; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * ID | ||||||
|  |      */ | ||||||
|  |     @TableId(type = IdType.ASSIGN_ID) | ||||||
|  |     private Long id; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 用户 ID | ||||||
|  |      */ | ||||||
|  |     private Long userId; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 密码 | ||||||
|  |      */ | ||||||
|  |     private String password; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 创建时间 | ||||||
|  |      */ | ||||||
|  |     @TableField(fill = FieldFill.INSERT) | ||||||
|  |     private LocalDateTime createTime; | ||||||
|  |  | ||||||
|  |     public UserPasswordHistoryDO(Long userId, String password) { | ||||||
|  |         this.userId = userId; | ||||||
|  |         this.password = password; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -31,7 +31,7 @@ public interface RoleDeptService { | |||||||
|      * |      * | ||||||
|      * @param deptIds 部门 ID 列表 |      * @param deptIds 部门 ID 列表 | ||||||
|      * @param roleId  角色 ID |      * @param roleId  角色 ID | ||||||
|      * @return true:成功;false:无变更/失败 |      * @return 是否新增成功(true:成功;false:无变更/失败) | ||||||
|      */ |      */ | ||||||
|     boolean add(List<Long> deptIds, Long roleId); |     boolean add(List<Long> deptIds, Long roleId); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ public interface RoleMenuService { | |||||||
|      * |      * | ||||||
|      * @param menuIds 菜单 ID 列表 |      * @param menuIds 菜单 ID 列表 | ||||||
|      * @param roleId  角色 ID |      * @param roleId  角色 ID | ||||||
|      * @return true:成功;false:无变更/失败 |      * @return 是否新增成功(true:成功;false:无变更/失败) | ||||||
|      */ |      */ | ||||||
|     boolean add(List<Long> menuIds, Long roleId); |     boolean add(List<Long> menuIds, Long roleId); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | /* | ||||||
|  |  * 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.service; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 用户历史密码业务接口 | ||||||
|  |  * | ||||||
|  |  * @author Charles7c | ||||||
|  |  * @since 2024/5/16 21:58 | ||||||
|  |  */ | ||||||
|  | public interface UserPasswordHistoryService { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 新增 | ||||||
|  |      * | ||||||
|  |      * @param userId   用户 ID | ||||||
|  |      * @param password 密码 | ||||||
|  |      * @param count    保留 N 个历史 | ||||||
|  |      */ | ||||||
|  |     void add(Long userId, String password, int count); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 密码是否为重复使用 | ||||||
|  |      * | ||||||
|  |      * @param userId   用户 ID | ||||||
|  |      * @param password 密码 | ||||||
|  |      * @param count    最近 N 次 | ||||||
|  |      * @return 是否为重复使用 | ||||||
|  |      */ | ||||||
|  |     boolean isPasswordReused(Long userId, String password, int count); | ||||||
|  | } | ||||||
| @@ -31,7 +31,7 @@ public interface UserRoleService { | |||||||
|      * |      * | ||||||
|      * @param roleIds 角色 ID 列表 |      * @param roleIds 角色 ID 列表 | ||||||
|      * @param userId  用户 ID |      * @param userId  用户 ID | ||||||
|      * @return true:成功;false:无变更/失败 |      * @return 是否新增成功(true:成功;false:无变更/失败) | ||||||
|      */ |      */ | ||||||
|     boolean add(List<Long> roleIds, Long userId); |     boolean add(List<Long> roleIds, Long userId); | ||||||
|  |  | ||||||
| @@ -54,7 +54,7 @@ public interface UserRoleService { | |||||||
|      * 根据角色 ID 判断是否已被用户关联 |      * 根据角色 ID 判断是否已被用户关联 | ||||||
|      * |      * | ||||||
|      * @param roleIds 角色 ID 列表 |      * @param roleIds 角色 ID 列表 | ||||||
|      * @return true:已关联;false:未关联 |      * @return 是否已关联(true:已关联;false:未关联) | ||||||
|      */ |      */ | ||||||
|     boolean isRoleIdExists(List<Long> roleIds); |     boolean isRoleIdExists(List<Long> roleIds); | ||||||
| } | } | ||||||
| @@ -145,5 +145,5 @@ public interface UserService extends BaseService<UserResp, UserDetailResp, UserQ | |||||||
|      * @param pwdResetTime 上次重置密码时间 |      * @param pwdResetTime 上次重置密码时间 | ||||||
|      * @return 是否过期 |      * @return 是否过期 | ||||||
|      */ |      */ | ||||||
|     Boolean isPasswordExpired(LocalDateTime pwdResetTime); |     boolean isPasswordExpired(LocalDateTime pwdResetTime); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,67 @@ | |||||||
|  | /* | ||||||
|  |  * 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.service.impl; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.collection.CollUtil; | ||||||
|  | import lombok.RequiredArgsConstructor; | ||||||
|  | import org.springframework.security.crypto.password.PasswordEncoder; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | import org.springframework.transaction.annotation.Transactional; | ||||||
|  | import top.continew.admin.system.mapper.UserPasswordHistoryMapper; | ||||||
|  | import top.continew.admin.system.model.entity.UserPasswordHistoryDO; | ||||||
|  | import top.continew.admin.system.service.UserPasswordHistoryService; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 用户历史密码业务实现 | ||||||
|  |  * | ||||||
|  |  * @author Charles7c | ||||||
|  |  * @since 2024/5/16 21:58 | ||||||
|  |  */ | ||||||
|  | @Service | ||||||
|  | @RequiredArgsConstructor | ||||||
|  | public class UserPasswordHistoryServiceImpl implements UserPasswordHistoryService { | ||||||
|  |  | ||||||
|  |     private final UserPasswordHistoryMapper baseMapper; | ||||||
|  |     private final PasswordEncoder passwordEncoder; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     @Transactional(rollbackFor = Exception.class) | ||||||
|  |     public void add(Long userId, String password, int count) { | ||||||
|  |         baseMapper.insert(new UserPasswordHistoryDO(userId, password)); | ||||||
|  |         // 删除过期历史密码 | ||||||
|  |         baseMapper.deleteExpired(userId, count); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean isPasswordReused(Long userId, String password, int count) { | ||||||
|  |         // 查询近 N 个历史密码 | ||||||
|  |         List<UserPasswordHistoryDO> list = baseMapper.lambdaQuery() | ||||||
|  |             .select(UserPasswordHistoryDO::getPassword) | ||||||
|  |             .eq(UserPasswordHistoryDO::getUserId, userId) | ||||||
|  |             .orderByDesc(UserPasswordHistoryDO::getCreateTime) | ||||||
|  |             .last("LIMIT %s".formatted(count)) | ||||||
|  |             .list(); | ||||||
|  |         if (CollUtil.isEmpty(list)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // 校验是否重复使用历史密码 | ||||||
|  |         List<String> passwordList = list.stream().map(UserPasswordHistoryDO::getPassword).toList(); | ||||||
|  |         return passwordList.stream().anyMatch(p -> passwordEncoder.matches(password, p)); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -88,6 +88,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes | |||||||
|     private final FileStorageService fileStorageService; |     private final FileStorageService fileStorageService; | ||||||
|     private final PasswordEncoder passwordEncoder; |     private final PasswordEncoder passwordEncoder; | ||||||
|     private final OptionService optionService; |     private final OptionService optionService; | ||||||
|  |     private final UserPasswordHistoryService userPasswordHistoryService; | ||||||
|     @Resource |     @Resource | ||||||
|     private DeptService deptService; |     private DeptService deptService; | ||||||
|     @Value("${avatar.support-suffix}") |     @Value("${avatar.support-suffix}") | ||||||
| @@ -192,6 +193,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  |     @Transactional(rollbackFor = Exception.class) | ||||||
|     public void updatePassword(String oldPassword, String newPassword, Long id) { |     public void updatePassword(String oldPassword, String newPassword, Long id) { | ||||||
|         CheckUtils.throwIfEqual(newPassword, oldPassword, "新密码不能与当前密码相同"); |         CheckUtils.throwIfEqual(newPassword, oldPassword, "新密码不能与当前密码相同"); | ||||||
|         UserDO user = super.getById(id); |         UserDO user = super.getById(id); | ||||||
| @@ -200,16 +202,17 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes | |||||||
|             CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, password), "当前密码错误"); |             CheckUtils.throwIf(!passwordEncoder.matches(oldPassword, password), "当前密码错误"); | ||||||
|         } |         } | ||||||
|         // 校验密码合法性 |         // 校验密码合法性 | ||||||
|         this.checkPassword(newPassword, user); |         int passwordReusePolicy = this.checkPassword(newPassword, user); | ||||||
|         // 更新密码和密码重置时间 |         // 更新密码和密码重置时间 | ||||||
|         user.setPassword(newPassword); |         user.setPassword(newPassword); | ||||||
|         user.setPwdResetTime(LocalDateTime.now()); |         user.setPwdResetTime(LocalDateTime.now()); | ||||||
|         baseMapper.updateById(user); |         baseMapper.updateById(user); | ||||||
|         onlineUserService.cleanByUserId(user.getId()); |         // 保存历史密码 | ||||||
|  |         userPasswordHistoryService.add(id, password, passwordReusePolicy); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public Boolean isPasswordExpired(LocalDateTime pwdResetTime) { |     public boolean isPasswordExpired(LocalDateTime pwdResetTime) { | ||||||
|         // 永久有效 |         // 永久有效 | ||||||
|         int passwordExpirationDays = optionService.getValueByCode2Int(PASSWORD_EXPIRATION_DAYS.name()); |         int passwordExpirationDays = optionService.getValueByCode2Int(PASSWORD_EXPIRATION_DAYS.name()); | ||||||
|         if (passwordExpirationDays <= SysConstants.NO) { |         if (passwordExpirationDays <= SysConstants.NO) { | ||||||
| @@ -343,7 +346,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes | |||||||
|      * @param password 密码 |      * @param password 密码 | ||||||
|      * @param user     用户信息 |      * @param user     用户信息 | ||||||
|      */ |      */ | ||||||
|     private void checkPassword(String password, UserDO user) { |     private int checkPassword(String password, UserDO user) { | ||||||
|         // 密码最小长度 |         // 密码最小长度 | ||||||
|         int passwordMinLength = optionService.getValueByCode2Int(PASSWORD_MIN_LENGTH.name()); |         int passwordMinLength = optionService.getValueByCode2Int(PASSWORD_MIN_LENGTH.name()); | ||||||
|         ValidationUtils.throwIf(StrUtil.length(password) < passwordMinLength, PASSWORD_MIN_LENGTH.getDescription() |         ValidationUtils.throwIf(StrUtil.length(password) < passwordMinLength, PASSWORD_MIN_LENGTH.getDescription() | ||||||
| @@ -362,6 +365,12 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes | |||||||
|         int passwordContainSpecialChar = optionService.getValueByCode2Int(PASSWORD_CONTAIN_SPECIAL_CHARACTERS.name()); |         int passwordContainSpecialChar = optionService.getValueByCode2Int(PASSWORD_CONTAIN_SPECIAL_CHARACTERS.name()); | ||||||
|         ValidationUtils.throwIf(passwordContainSpecialChar == SysConstants.YES && !ReUtil |         ValidationUtils.throwIf(passwordContainSpecialChar == SysConstants.YES && !ReUtil | ||||||
|             .isMatch(RegexConstants.SPECIAL_CHARACTER, password), PASSWORD_CONTAIN_SPECIAL_CHARACTERS.getDescription()); |             .isMatch(RegexConstants.SPECIAL_CHARACTER, password), PASSWORD_CONTAIN_SPECIAL_CHARACTERS.getDescription()); | ||||||
|  |         // 密码重复使用规则 | ||||||
|  |         int passwordReusePolicy = optionService.getValueByCode2Int(PASSWORD_REUSE_POLICY.name()); | ||||||
|  |         ValidationUtils.throwIf(userPasswordHistoryService.isPasswordReused(user | ||||||
|  |             .getId(), password, passwordReusePolicy), PASSWORD_REUSE_POLICY.getDescription() | ||||||
|  |                 .formatted(passwordReusePolicy)); | ||||||
|  |         return passwordReusePolicy; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -0,0 +1,16 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||||
|  | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > | ||||||
|  | <mapper namespace="top.continew.admin.system.mapper.UserPasswordHistoryMapper"> | ||||||
|  |     <delete id="deleteExpired"> | ||||||
|  |         DELETE FROM sys_user_password_history | ||||||
|  |         WHERE id NOT IN ( | ||||||
|  |             SELECT * FROM ( | ||||||
|  |                 SELECT id | ||||||
|  |                 FROM sys_user_password_history | ||||||
|  |                 WHERE user_id = #{userId} | ||||||
|  |                 ORDER BY create_time DESC | ||||||
|  |                 LIMIT #{count} | ||||||
|  |             ) t1 | ||||||
|  |         ) | ||||||
|  |     </delete> | ||||||
|  | </mapper> | ||||||
| @@ -121,7 +121,7 @@ VALUES | |||||||
| ('密码有效期(天)', 'PASSWORD_EXPIRATION_DAYS', NULL, '0', '取值范围为 0-999(0 表示永久有效)。', NULL, NULL), | ('密码有效期(天)', 'PASSWORD_EXPIRATION_DAYS', NULL, '0', '取值范围为 0-999(0 表示永久有效)。', NULL, NULL), | ||||||
| ('密码重复使用规则', 'PASSWORD_REUSE_POLICY', NULL, '5', '不允许使用最近 N 次密码,取值范围为 3-32。', NULL, NULL), | ('密码重复使用规则', 'PASSWORD_REUSE_POLICY', NULL, '5', '不允许使用最近 N 次密码,取值范围为 3-32。', NULL, NULL), | ||||||
| ('密码最小长度', 'PASSWORD_MIN_LENGTH', NULL, '8', '取值范围为 8-32。', NULL, NULL), | ('密码最小长度', 'PASSWORD_MIN_LENGTH', NULL, '8', '取值范围为 8-32。', NULL, NULL), | ||||||
| ('密码是否允许包含正反序账号名', 'PASSWORD_ALLOW_CONTAIN_USERNAME', NULL, '0', '', NULL, NULL), | ('密码是否允许包含正反序账号名', 'PASSWORD_ALLOW_CONTAIN_USERNAME', NULL, '1', '', NULL, NULL), | ||||||
| ('密码是否必须包含特殊字符', 'PASSWORD_CONTAIN_SPECIAL_CHARACTERS', NULL, '0', '', NULL, NULL); | ('密码是否必须包含特殊字符', 'PASSWORD_CONTAIN_SPECIAL_CHARACTERS', NULL, '0', '', NULL, NULL); | ||||||
|  |  | ||||||
| -- 初始化默认字典 | -- 初始化默认字典 | ||||||
|   | |||||||
| @@ -95,6 +95,15 @@ CREATE TABLE IF NOT EXISTS `sys_user` ( | |||||||
|     INDEX `idx_update_user`(`update_user`) USING BTREE |     INDEX `idx_update_user`(`update_user`) USING BTREE | ||||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; | ||||||
|  |  | ||||||
|  | CREATE TABLE IF NOT EXISTS `sys_user_password_history` ( | ||||||
|  |     `id`          bigint(20)   NOT NULL COMMENT 'ID', | ||||||
|  |     `user_id`     bigint(20)   NOT NULL COMMENT '用户ID', | ||||||
|  |     `password`    varchar(255) NOT NULL COMMENT '密码', | ||||||
|  |     `create_time` datetime     NOT NULL COMMENT '创建时间', | ||||||
|  |     PRIMARY KEY (`id`) USING BTREE, | ||||||
|  |     INDEX `idx_user_id`(`user_id`) USING BTREE | ||||||
|  | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户历史密码表'; | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS `sys_user_social` ( | CREATE TABLE IF NOT EXISTS `sys_user_social` ( | ||||||
|     `source`          varchar(255) NOT NULL     COMMENT '来源', |     `source`          varchar(255) NOT NULL     COMMENT '来源', | ||||||
|     `open_id`         varchar(255) NOT NULL     COMMENT '开放ID', |     `open_id`         varchar(255) NOT NULL     COMMENT '开放ID', | ||||||
|   | |||||||
| @@ -121,7 +121,7 @@ VALUES | |||||||
| ('密码有效期(天)', 'PASSWORD_EXPIRATION_DAYS', NULL, '0', '取值范围为 0-999(0 表示永久有效)。', NULL, NULL), | ('密码有效期(天)', 'PASSWORD_EXPIRATION_DAYS', NULL, '0', '取值范围为 0-999(0 表示永久有效)。', NULL, NULL), | ||||||
| ('密码重复使用规则', 'PASSWORD_REUSE_POLICY', NULL, '5', '不允许使用最近 N 次密码,取值范围为 3-32。', NULL, NULL), | ('密码重复使用规则', 'PASSWORD_REUSE_POLICY', NULL, '5', '不允许使用最近 N 次密码,取值范围为 3-32。', NULL, NULL), | ||||||
| ('密码最小长度', 'PASSWORD_MIN_LENGTH', NULL, '8', '取值范围为 8-32。', NULL, NULL), | ('密码最小长度', 'PASSWORD_MIN_LENGTH', NULL, '8', '取值范围为 8-32。', NULL, NULL), | ||||||
| ('密码是否允许包含正反序账号名', 'PASSWORD_ALLOW_CONTAIN_USERNAME', NULL, '0', '', NULL, NULL), | ('密码是否允许包含正反序账号名', 'PASSWORD_ALLOW_CONTAIN_USERNAME', NULL, '1', '', NULL, NULL), | ||||||
| ('密码是否必须包含特殊字符', 'PASSWORD_CONTAIN_SPECIAL_CHARACTERS', NULL, '0', '', NULL, NULL); | ('密码是否必须包含特殊字符', 'PASSWORD_CONTAIN_SPECIAL_CHARACTERS', NULL, '0', '', NULL, NULL); | ||||||
|  |  | ||||||
| -- 初始化默认字典 | -- 初始化默认字典 | ||||||
|   | |||||||
| @@ -158,6 +158,20 @@ COMMENT ON COLUMN "sys_user"."update_user"    IS '修改人'; | |||||||
| COMMENT ON COLUMN "sys_user"."update_time"    IS '修改时间'; | COMMENT ON COLUMN "sys_user"."update_time"    IS '修改时间'; | ||||||
| COMMENT ON TABLE  "sys_user"                  IS '用户表'; | COMMENT ON TABLE  "sys_user"                  IS '用户表'; | ||||||
|  |  | ||||||
|  | CREATE TABLE IF NOT EXISTS "sys_user_password_history" ( | ||||||
|  |     "id"          int8         NOT NULL, | ||||||
|  |     "user_id"     int8         NOT NULL, | ||||||
|  |     "password"    varchar(255) NOT NULL, | ||||||
|  |     "create_time" timestamp    NOT NULL, | ||||||
|  |     PRIMARY KEY ("id") | ||||||
|  | ); | ||||||
|  | CREATE INDEX "idx_uph_user_id" ON "sys_user_password_history" ("user_id"); | ||||||
|  | COMMENT ON COLUMN "sys_user_password_history"."id"          IS 'ID'; | ||||||
|  | COMMENT ON COLUMN "sys_user_password_history"."user_id"     IS '用户ID'; | ||||||
|  | COMMENT ON COLUMN "sys_user_password_history"."password"    IS '密码'; | ||||||
|  | COMMENT ON COLUMN "sys_user_password_history"."create_time" IS '创建时间'; | ||||||
|  | COMMENT ON TABLE  "sys_user_password_history"               IS '用户历史密码表'; | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS "sys_user_social" ( | CREATE TABLE IF NOT EXISTS "sys_user_social" ( | ||||||
|     "source"          varchar(255) NOT NULL, |     "source"          varchar(255) NOT NULL, | ||||||
|     "open_id"         varchar(255) NOT NULL, |     "open_id"         varchar(255) NOT NULL, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user