refactor: 使用枚举方法优化部分密码策略校验

This commit is contained in:
2024-05-17 20:13:35 +08:00
parent 3994142ace
commit 1427c13b7a
2 changed files with 109 additions and 54 deletions

View File

@@ -16,9 +16,16 @@
package top.continew.admin.system.enums;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
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.system.model.entity.UserDO;
import top.continew.admin.system.service.UserPasswordHistoryService;
import top.continew.starter.core.util.validate.ValidationUtils;
/**
* 密码策略枚举
@@ -31,47 +38,110 @@ import top.continew.admin.common.constant.SysConstants;
@RequiredArgsConstructor
public enum PasswordPolicyEnum {
/**
* 登录密码错误锁定账号的次数
*/
PASSWORD_ERROR_LOCK_COUNT(null, SysConstants.NO, 10),
/**
* 登录密码错误锁定账号的时间min
*/
PASSWORD_ERROR_LOCK_MINUTES(null, 1, 1440),
/**
* 密码到期提前提示(天)
*/
PASSWORD_EXPIRATION_WARNING_DAYS(null, SysConstants.NO, Integer.MAX_VALUE),
/**
* 密码有效期(天)
*/
PASSWORD_EXPIRATION_DAYS(null, SysConstants.NO, 999),
/**
* 密码重复使用规则
*/
PASSWORD_REUSE_POLICY("不允许使用最近 %s 次的历史密码", 3, 32),
/**
* 密码最小长度
*/
PASSWORD_MIN_LENGTH("密码最小长度为 %s 个字符", 8, 32),
/**
* 密码是否允许包含正反序账号名
*/
PASSWORD_ALLOW_CONTAIN_USERNAME("密码不允许包含正反序账号名", SysConstants.NO, SysConstants.YES),
PASSWORD_MIN_LENGTH("密码最小长度为 %s 个字符", 8, 32) {
@Override
public void validate(String password, int policyValue, UserDO user) {
// 最小长度校验
ValidationUtils.throwIf(StrUtil.length(password) < policyValue, this.getDescription()
.formatted(policyValue));
// 完整校验
int passwordMaxLength = this.getMax();
ValidationUtils.throwIf(!ReUtil.isMatch(RegexConstants.PASSWORD_TEMPLATE
.formatted(policyValue, passwordMaxLength), password), "密码长度为 {}-{} 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字", policyValue, passwordMaxLength);
}
},
/**
* 密码是否必须包含特殊字符
*/
PASSWORD_CONTAIN_SPECIAL_CHARACTERS("密码必须包含特殊字符", SysConstants.NO, SysConstants.YES),;
PASSWORD_CONTAIN_SPECIAL_CHARACTERS("密码必须包含特殊字符", SysConstants.NO, SysConstants.YES) {
@Override
public void validate(String password, int policyValue, UserDO user) {
ValidationUtils.throwIf(policyValue == SysConstants.YES && !ReUtil
.isMatch(RegexConstants.SPECIAL_CHARACTER, password), this.getDescription());
}
},
/**
* 密码是否允许包含正反序账号名
*/
PASSWORD_ALLOW_CONTAIN_USERNAME("密码不允许包含正反序账号名", SysConstants.NO, SysConstants.YES) {
@Override
public void validate(String password, int policyValue, UserDO user) {
if (policyValue <= SysConstants.NO) {
String username = user.getUsername();
ValidationUtils.throwIf(StrUtil.containsAnyIgnoreCase(password, username, StrUtil
.reverse(username)), this.getDescription());
}
}
},
/**
* 密码重复使用规则
*/
PASSWORD_REUSE_POLICY("不允许使用最近 %s 次的历史密码", 3, 32) {
@Override
public void validate(String password, int policyValue, UserDO user) {
UserPasswordHistoryService userPasswordHistoryService = SpringUtil
.getBean(UserPasswordHistoryService.class);
ValidationUtils.throwIf(userPasswordHistoryService.isPasswordReused(user
.getId(), password, policyValue), this.getDescription().formatted(policyValue));
}
},
/**
* 登录密码错误锁定账号的次数
*/
PASSWORD_ERROR_LOCK_COUNT(null, SysConstants.NO, 10) {
@Override
public void validate(String password, int policyValue, UserDO user) {
// 无需此处校验
}
},
/**
* 登录密码错误锁定账号的时间min
*/
PASSWORD_ERROR_LOCK_MINUTES(null, 1, 1440) {
@Override
public void validate(String password, int policyValue, UserDO user) {
// 无需此处校验
}
},
/**
* 密码到期提前提示(天)
*/
PASSWORD_EXPIRATION_WARNING_DAYS(null, SysConstants.NO, Integer.MAX_VALUE) {
@Override
public void validate(String password, int policyValue, UserDO user) {
// 无需此处校验
}
},
/**
* 密码有效期(天)
*/
PASSWORD_EXPIRATION_DAYS(null, SysConstants.NO, 999) {
@Override
public void validate(String password, int policyValue, UserDO user) {
// 无需此处校验
}
},;
private final String description;
private final Integer min;
private final Integer max;
/**
* 校验
*
* @param password 密码
* @param policyValue 策略值
* @param user 用户信息
*/
public abstract void validate(String password, int policyValue, UserDO user);
}

View File

@@ -20,7 +20,6 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.anno.CacheInvalidate;
import com.alicp.jetcache.anno.CacheType;
@@ -39,7 +38,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import top.continew.admin.auth.service.OnlineUserService;
import top.continew.admin.common.constant.CacheConstants;
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.util.helper.LoginHelper;
@@ -56,7 +54,6 @@ import top.continew.admin.system.model.resp.UserResp;
import top.continew.admin.system.service.*;
import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.util.validate.CheckUtils;
import top.continew.starter.core.util.validate.ValidationUtils;
import top.continew.starter.extension.crud.model.query.PageQuery;
import top.continew.starter.extension.crud.model.resp.PageResp;
import top.continew.starter.extension.crud.service.CommonUserService;
@@ -348,28 +345,16 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
*/
private int checkPassword(String password, UserDO user) {
// 密码最小长度
int passwordMinLength = optionService.getValueByCode2Int(PASSWORD_MIN_LENGTH.name());
ValidationUtils.throwIf(StrUtil.length(password) < passwordMinLength, PASSWORD_MIN_LENGTH.getDescription()
.formatted(passwordMinLength));
// 密码是否允许包含正反序账号名
int passwordAllowContainUsername = optionService.getValueByCode2Int(PASSWORD_ALLOW_CONTAIN_USERNAME.name());
if (passwordAllowContainUsername == SysConstants.NO) {
String username = user.getUsername();
ValidationUtils.throwIf(StrUtil.containsAnyIgnoreCase(password, username, StrUtil
.reverse(username)), PASSWORD_ALLOW_CONTAIN_USERNAME.getDescription());
}
int passwordMaxLength = PASSWORD_MIN_LENGTH.getMax();
ValidationUtils.throwIf(!ReUtil.isMatch(RegexConstants.PASSWORD_TEMPLATE
.formatted(passwordMinLength, passwordMaxLength), password), "密码长度为 {}-{} 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字", passwordMinLength, passwordMaxLength);
PASSWORD_MIN_LENGTH.validate(password, optionService.getValueByCode2Int(PASSWORD_MIN_LENGTH.name()), user);
// 密码是否必须包含特殊字符
int passwordContainSpecialChar = optionService.getValueByCode2Int(PASSWORD_CONTAIN_SPECIAL_CHARACTERS.name());
ValidationUtils.throwIf(passwordContainSpecialChar == SysConstants.YES && !ReUtil
.isMatch(RegexConstants.SPECIAL_CHARACTER, password), PASSWORD_CONTAIN_SPECIAL_CHARACTERS.getDescription());
PASSWORD_CONTAIN_SPECIAL_CHARACTERS.validate(password, optionService
.getValueByCode2Int(PASSWORD_CONTAIN_SPECIAL_CHARACTERS.name()), user);
// 密码是否允许包含正反序账号名
PASSWORD_ALLOW_CONTAIN_USERNAME.validate(password, optionService
.getValueByCode2Int(PASSWORD_ALLOW_CONTAIN_USERNAME.name()), user);
// 密码重复使用规则
int passwordReusePolicy = optionService.getValueByCode2Int(PASSWORD_REUSE_POLICY.name());
ValidationUtils.throwIf(userPasswordHistoryService.isPasswordReused(user
.getId(), password, passwordReusePolicy), PASSWORD_REUSE_POLICY.getDescription()
.formatted(passwordReusePolicy));
PASSWORD_REUSE_POLICY.validate(password, passwordReusePolicy, user);
return passwordReusePolicy;
}