feat: 新增账号密码策略
This commit is contained in:
parent
cca46d159e
commit
bcf8279d3d
@ -77,6 +77,7 @@ public class SecurityConfig {
|
||||
// .requestMatchers("/threedroamb/**").permitAll()
|
||||
// .requestMatchers("/overview/**").permitAll()
|
||||
.requestMatchers("/wt/**").permitAll()
|
||||
.requestMatchers("/system/acctPasswordPolicy/**").permitAll()
|
||||
.requestMatchers("/fb/**").permitAll()
|
||||
// .requestMatchers("/base/**").permitAll()
|
||||
// .requestMatchers("/zq/**").permitAll()
|
||||
|
||||
@ -0,0 +1,139 @@
|
||||
package com.yfd.platform.system.controller;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.yfd.platform.common.DataSourceRequest;
|
||||
import com.yfd.platform.config.ResponseResult;
|
||||
import com.yfd.platform.system.domain.SysAcctPasswordPolicy;
|
||||
import com.yfd.platform.system.service.ISysAcctPasswordPolicyService;
|
||||
import com.yfd.platform.system.service.IUserService;
|
||||
import com.yfd.platform.utils.DataSourceRequestUtil;
|
||||
import com.yfd.platform.utils.SecurityUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 账号密码策略 前端控制器
|
||||
* </p>
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/system/acctPasswordPolicy")
|
||||
@Tag(name = "账号密码策略管理")
|
||||
public class SysAcctPasswordPolicyController {
|
||||
|
||||
@Resource
|
||||
private ISysAcctPasswordPolicyService policyService;
|
||||
|
||||
@Resource
|
||||
private IUserService userService;
|
||||
|
||||
@GetMapping("/current")
|
||||
@Operation(summary = "获取当前生效的密码策略")
|
||||
public ResponseResult current() {
|
||||
SysAcctPasswordPolicy policy = policyService.getCurrentPolicy();
|
||||
return policy == null
|
||||
? ResponseResult.error("未配置密码策略")
|
||||
: ResponseResult.successData(policy);
|
||||
}
|
||||
|
||||
@GetMapping("/getById")
|
||||
@Operation(summary = "根据ID查询密码策略")
|
||||
public ResponseResult getById(@RequestParam String id) {
|
||||
SysAcctPasswordPolicy policy = policyService.getById(id);
|
||||
return policy == null
|
||||
? ResponseResult.error("策略不存在")
|
||||
: ResponseResult.successData(policy);
|
||||
}
|
||||
|
||||
@PostMapping("/queryPageList")
|
||||
@Operation(summary = "分页查询密码策略列表")
|
||||
public ResponseResult queryPageList(@RequestBody DataSourceRequest request) {
|
||||
Page<SysAcctPasswordPolicy> page = DataSourceRequestUtil.executeQuery(request, SysAcctPasswordPolicy.class, policyService);
|
||||
return ResponseResult.successData(page);
|
||||
}
|
||||
|
||||
@PostMapping("/list")
|
||||
@Operation(summary = "查询密码策略列表(不分页)")
|
||||
public ResponseResult list(@RequestBody DataSourceRequest request) {
|
||||
List<SysAcctPasswordPolicy> list = DataSourceRequestUtil.executeList(request, SysAcctPasswordPolicy.class, policyService);
|
||||
return ResponseResult.successData(list);
|
||||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
@Operation(summary = "新增密码策略")
|
||||
public ResponseResult add(@RequestBody SysAcctPasswordPolicy policy) {
|
||||
if (StrUtil.isBlank(policy.getName())) {
|
||||
return ResponseResult.error("策略名称不能为空");
|
||||
}
|
||||
policy.setId(IdUtil.fastSimpleUUID());
|
||||
// policy.setRecordUser(SecurityUtils.getUserId());
|
||||
policy.setRecordUser("admin");
|
||||
policy.setRecordTime(new Date());
|
||||
policy.setIsDeleted(0);
|
||||
|
||||
boolean ok = policyService.save(policy);
|
||||
return ok ? ResponseResult.success("新增成功") : ResponseResult.error("新增失败");
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
@Operation(summary = "修改密码策略")
|
||||
public ResponseResult update(@RequestBody SysAcctPasswordPolicy policy) {
|
||||
if (StrUtil.isBlank(policy.getId())) {
|
||||
return ResponseResult.error("ID不能为空");
|
||||
}
|
||||
SysAcctPasswordPolicy exist = policyService.getById(policy.getId());
|
||||
if (exist == null) {
|
||||
return ResponseResult.error("策略不存在");
|
||||
}
|
||||
policy.setModifyUser(userService.getUsername());
|
||||
policy.setModifyTime(new Date());
|
||||
|
||||
boolean ok = policyService.updateById(policy);
|
||||
return ok ? ResponseResult.success("修改成功") : ResponseResult.error("修改失败");
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
@Operation(summary = "删除密码策略(软删除)")
|
||||
public ResponseResult delete(@RequestBody List<String> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return ResponseResult.error("ID不能为空");
|
||||
}
|
||||
Date now = new Date();
|
||||
String username = userService.getUsername();
|
||||
for (String id : ids) {
|
||||
SysAcctPasswordPolicy policy = policyService.getById(id);
|
||||
if (policy != null) {
|
||||
policy.setIsDeleted(1);
|
||||
policy.setDeleteUser(username);
|
||||
policy.setDeleteTime(now);
|
||||
policyService.updateById(policy);
|
||||
}
|
||||
}
|
||||
return ResponseResult.success("删除成功");
|
||||
}
|
||||
|
||||
@PostMapping("/validatePassword")
|
||||
@Operation(summary = "根据当前策略校验密码复杂度")
|
||||
public ResponseResult validatePassword(@RequestParam String password,
|
||||
@RequestParam(required = false) String username) {
|
||||
SysAcctPasswordPolicy policy = policyService.getCurrentPolicy();
|
||||
if (policy == null) {
|
||||
return ResponseResult.error("未配置密码策略");
|
||||
}
|
||||
String errMsg = policyService.validatePassword(policy, password, username);
|
||||
if (errMsg != null) {
|
||||
return ResponseResult.error(errMsg);
|
||||
}
|
||||
return ResponseResult.success("密码校验通过");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,189 @@
|
||||
package com.yfd.platform.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 账号密码策略表
|
||||
* </p>
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("SYS_ACCT_PASSWORD_POLICY")
|
||||
public class SysAcctPasswordPolicy implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
private String id;
|
||||
|
||||
/** 密码策略标识 */
|
||||
private String code;
|
||||
|
||||
/** 策略名称 */
|
||||
private String name;
|
||||
|
||||
/** 用户名敏感性校验 */
|
||||
private Integer usernameSensitiveValid;
|
||||
|
||||
/** 密码敏感性校验 */
|
||||
private Integer passwordSensitiveValid;
|
||||
|
||||
/** 启用短信重置密码 */
|
||||
private Integer enableSmsResetPwd;
|
||||
|
||||
/** 启用邮箱重置密码 */
|
||||
private Integer enableEmailResetPwd;
|
||||
|
||||
/** 启用输入密码 */
|
||||
private Integer enableInputPassword;
|
||||
|
||||
/** 启用默认密码 */
|
||||
private Integer enableDefaultPassword;
|
||||
|
||||
/** 默认密码 */
|
||||
private String defaultPassword;
|
||||
|
||||
/** 密码最小长度 */
|
||||
private Integer minLength;
|
||||
|
||||
/** 密码最大长度 */
|
||||
private Integer maxLength;
|
||||
|
||||
/** 最大密码错误次数 */
|
||||
private Integer maxErrorNumber;
|
||||
|
||||
/** 密码必须包含字符类型 */
|
||||
private String passwordCharsRequire;
|
||||
|
||||
/** 密码数字数量要求 */
|
||||
private Integer digitsCount;
|
||||
|
||||
/** 密码小写字母数量要求 */
|
||||
private Integer lowercaseCount;
|
||||
|
||||
/** 密码大写字母数量要求 */
|
||||
private Integer uppercaseCount;
|
||||
|
||||
/** 特殊字符数量要求 */
|
||||
private Integer specialCharCount;
|
||||
|
||||
/** 密码不可与用户名相同 */
|
||||
private Integer notUsername;
|
||||
|
||||
/** 密码正则表达式 */
|
||||
private String regularExpression;
|
||||
|
||||
/** 不可使用最近N次密码 */
|
||||
private Integer notRecentCount;
|
||||
|
||||
/** 启用密码策略 */
|
||||
private Integer enablePasswordPolicy;
|
||||
|
||||
/** 启用安全策略 */
|
||||
private Integer enableSecurityPolicy;
|
||||
|
||||
/** 启用账户锁定 */
|
||||
private Integer enableLock;
|
||||
|
||||
/** 锁定时长(秒) */
|
||||
private Integer lockedExpireTime;
|
||||
|
||||
/** 启用验证码 */
|
||||
private Integer enableCaptcha;
|
||||
|
||||
/** 验证码类型 */
|
||||
private String captureType;
|
||||
|
||||
/** 触发验证码的错误次数 */
|
||||
private Integer maxCheckCaptcha;
|
||||
|
||||
/** Web端多端登录 */
|
||||
private Integer enableWebMultipleLogin;
|
||||
|
||||
/** 移动端多端登录 */
|
||||
private Integer enableAppMultipleLogin;
|
||||
|
||||
/** 密码更新频率(天) */
|
||||
private Integer passwordUpdateRate;
|
||||
|
||||
/** 规则变更时强制修改密码 */
|
||||
private Integer forceModifyPwdRuleModify;
|
||||
|
||||
/** 密码修改提醒周期(天) */
|
||||
private Integer passwordReminderPeriod;
|
||||
|
||||
/** 首次登录强制修改密码 */
|
||||
private Integer forceModifyPassword;
|
||||
|
||||
/** 允许账号登录 */
|
||||
private Integer enableAccountLogin;
|
||||
|
||||
/** 修改密码后需重新登录 */
|
||||
private Integer loginAgain;
|
||||
|
||||
/** 允许短信登录 */
|
||||
private Integer enableSmsLogin;
|
||||
|
||||
/** 启用随机密码 */
|
||||
private Integer enableRandomPassword;
|
||||
|
||||
/** 启用数据加密 */
|
||||
private Integer enableDataSecurity;
|
||||
|
||||
/** 是否全局策略 */
|
||||
private Integer isBelongGlobal;
|
||||
|
||||
/** 是否双重验证 */
|
||||
private Integer isTwoFactorAuth;
|
||||
|
||||
/** 创建人 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String recordUser;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date recordTime;
|
||||
|
||||
/** 修改人 */
|
||||
@TableField(fill = FieldFill.UPDATE)
|
||||
private String modifyUser;
|
||||
|
||||
/** 修改时间 */
|
||||
@TableField(fill = FieldFill.UPDATE)
|
||||
private Date modifyTime;
|
||||
|
||||
/** 是否已删除 0=未删除 1=已删除 */
|
||||
@TableLogic
|
||||
private Integer isDeleted;
|
||||
|
||||
/** 删除人 */
|
||||
private String deleteUser;
|
||||
|
||||
/** 删除时间 */
|
||||
private Date deleteTime;
|
||||
|
||||
/** 过滤内容 */
|
||||
private String filterContent;
|
||||
|
||||
/** 排序 */
|
||||
private Integer orderIndex;
|
||||
|
||||
/** 启用验证码类型 */
|
||||
private String enableCaptchaType;
|
||||
|
||||
/** 启用企业微信登录 */
|
||||
private Integer enableEnterpriseWechatLogin;
|
||||
|
||||
/** 启用钉钉登录 */
|
||||
private Integer enableDingdingLogin;
|
||||
|
||||
/** 启用微信登录 */
|
||||
private Integer enableWechatLogin;
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.yfd.platform.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.yfd.platform.system.domain.SysAcctPasswordPolicy;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 账号密码策略表 Mapper 接口
|
||||
* </p>
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysAcctPasswordPolicyMapper extends BaseMapper<SysAcctPasswordPolicy> {
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.yfd.platform.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.yfd.platform.system.domain.SysAcctPasswordPolicy;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 账号密码策略表 服务类
|
||||
* </p>
|
||||
*/
|
||||
public interface ISysAcctPasswordPolicyService extends IService<SysAcctPasswordPolicy> {
|
||||
|
||||
/**
|
||||
* 获取当前生效的策略(取排序最小且未删除的那条)
|
||||
*/
|
||||
SysAcctPasswordPolicy getCurrentPolicy();
|
||||
|
||||
/**
|
||||
* 根据策略校验密码复杂度
|
||||
*
|
||||
* @param password 待校验的密码
|
||||
* @param username 关联的用户名(用于NOT_USERNAME校验)
|
||||
* @return null=校验通过,否则返回错误提示
|
||||
*/
|
||||
String validatePassword(SysAcctPasswordPolicy policy, String password, String username);
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
package com.yfd.platform.system.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yfd.platform.system.domain.SysAcctPasswordPolicy;
|
||||
import com.yfd.platform.system.mapper.SysAcctPasswordPolicyMapper;
|
||||
import com.yfd.platform.system.service.ISysAcctPasswordPolicyService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 账号密码策略表 服务实现类
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
public class SysAcctPasswordPolicyServiceImpl extends ServiceImpl<SysAcctPasswordPolicyMapper, SysAcctPasswordPolicy>
|
||||
implements ISysAcctPasswordPolicyService {
|
||||
|
||||
@Override
|
||||
public SysAcctPasswordPolicy getCurrentPolicy() {
|
||||
LambdaQueryWrapper<SysAcctPasswordPolicy> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(SysAcctPasswordPolicy::getIsDeleted, 0)
|
||||
.eq(SysAcctPasswordPolicy::getEnablePasswordPolicy, 1)
|
||||
.orderByAsc(SysAcctPasswordPolicy::getOrderIndex)
|
||||
.last("LIMIT 1");
|
||||
return getOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String validatePassword(SysAcctPasswordPolicy policy, String password, String username) {
|
||||
if (policy == null || StrUtil.isBlank(password)) {
|
||||
return "密码不能为空";
|
||||
}
|
||||
|
||||
// 1. 密码长度校验
|
||||
if (policy.getMinLength() != null && password.length() < policy.getMinLength()) {
|
||||
return "密码长度不能少于" + policy.getMinLength() + "位";
|
||||
}
|
||||
if (policy.getMaxLength() != null && password.length() > policy.getMaxLength()) {
|
||||
return "密码长度不能超过" + policy.getMaxLength() + "位";
|
||||
}
|
||||
|
||||
// 2. 密码与用户名不可相同
|
||||
if (isEnabled(policy.getNotUsername()) && StrUtil.isNotBlank(username) && username.equals(password)) {
|
||||
return "密码不能与用户名相同";
|
||||
}
|
||||
|
||||
// 3. 字符类型数量校验
|
||||
int digits = 0, lowercase = 0, uppercase = 0, special = 0;
|
||||
for (char c : password.toCharArray()) {
|
||||
if (Character.isDigit(c)) {
|
||||
digits++;
|
||||
} else if (Character.isLowerCase(c)) {
|
||||
lowercase++;
|
||||
} else if (Character.isUpperCase(c)) {
|
||||
uppercase++;
|
||||
} else {
|
||||
special++;
|
||||
}
|
||||
}
|
||||
|
||||
if (policy.getDigitsCount() != null && digits < policy.getDigitsCount()) {
|
||||
return "密码至少包含" + policy.getDigitsCount() + "个数字";
|
||||
}
|
||||
if (policy.getLowercaseCount() != null && lowercase < policy.getLowercaseCount()) {
|
||||
return "密码至少包含" + policy.getLowercaseCount() + "个小写字母";
|
||||
}
|
||||
if (policy.getUppercaseCount() != null && uppercase < policy.getUppercaseCount()) {
|
||||
return "密码至少包含" + policy.getUppercaseCount() + "个大写字母";
|
||||
}
|
||||
if (policy.getSpecialCharCount() != null && special < policy.getSpecialCharCount()) {
|
||||
return "密码至少包含" + policy.getSpecialCharCount() + "个特殊字符";
|
||||
}
|
||||
|
||||
// 4. 正则表达式校验
|
||||
if (StrUtil.isNotBlank(policy.getRegularExpression())) {
|
||||
try {
|
||||
if (!Pattern.matches(policy.getRegularExpression(), password)) {
|
||||
return "密码格式不符合要求";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 正则不合法则跳过
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isEnabled(Integer value) {
|
||||
return value != null && value == 1;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user