Skip to content

Commit

Permalink
refactor: 使用枚举方法优化部分密码策略校验
Browse files Browse the repository at this point in the history
  • Loading branch information
Charles7c committed May 17, 2024
1 parent 3994142 commit 1427c13
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
* 密码策略枚举
Expand All @@ -32,46 +39,109 @@
public enum PasswordPolicyEnum {

/**
* 登录密码错误锁定账号的次数
* 密码最小长度
*/
PASSWORD_ERROR_LOCK_COUNT(null, SysConstants.NO, 10),
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);
}
},

/**
* 登录密码错误锁定账号的时间(min)
* 密码是否必须包含特殊字符
*/
PASSWORD_ERROR_LOCK_MINUTES(null, 1, 1440),
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_EXPIRATION_WARNING_DAYS(null, SysConstants.NO, Integer.MAX_VALUE),
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_EXPIRATION_DAYS(null, SysConstants.NO, 999),
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_REUSE_POLICY("不允许使用最近 %s 次的历史密码", 3, 32),
PASSWORD_ERROR_LOCK_COUNT(null, SysConstants.NO, 10) {
@Override
public void validate(String password, int policyValue, UserDO user) {
// 无需此处校验
}
},

/**
* 密码最小长度
* 登录密码错误锁定账号的时间(min)
*/
PASSWORD_MIN_LENGTH("密码最小长度为 %s 个字符", 8, 32),
PASSWORD_ERROR_LOCK_MINUTES(null, 1, 1440) {
@Override
public void validate(String password, int policyValue, UserDO user) {
// 无需此处校验
}
},

/**
* 密码是否允许包含正反序账号名
* 密码到期提前提示(天)
*/
PASSWORD_ALLOW_CONTAIN_USERNAME("密码不允许包含正反序账号名", SysConstants.NO, SysConstants.YES),
PASSWORD_EXPIRATION_WARNING_DAYS(null, SysConstants.NO, Integer.MAX_VALUE) {
@Override
public void validate(String password, int policyValue, UserDO user) {
// 无需此处校验
}
},

/**
* 密码是否必须包含特殊字符
* 密码有效期(天)
*/
PASSWORD_CONTAIN_SPECIAL_CHARACTERS("密码必须包含特殊字符", SysConstants.NO, SysConstants.YES),;
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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
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;
Expand All @@ -39,7 +38,6 @@
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;
Expand All @@ -56,7 +54,6 @@
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;
Expand Down Expand Up @@ -348,28 +345,16 @@ protected void afterAdd(UserReq req, UserDO user) {
*/
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;
}

Expand Down

0 comments on commit 1427c13

Please sign in to comment.