feat: 支持账号导入与强制改密

- 新增账号导入模板下载、导入校验和默认密码重置标记

- 支持管理员重置密码并在登录后强制跳转修改密码

- 管理端与用户中心接入强密码校验和密码重置流程
This commit is contained in:
2026-03-18 21:56:05 +08:00
parent 14c78d54f5
commit 5d3c7d8692
40 changed files with 1720 additions and 142 deletions

View File

@@ -1,27 +1,32 @@
package tech.easyflow.admin.controller.system;
import tech.easyflow.common.constant.enums.EnumAccountType;
import tech.easyflow.common.constant.enums.EnumDataStatus;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.util.StringUtil;
import tech.easyflow.common.web.controller.BaseCurdController;
import tech.easyflow.common.web.jsonbody.JsonBody;
import tech.easyflow.log.annotation.LogRecord;
import tech.easyflow.system.entity.SysAccount;
import tech.easyflow.system.service.SysAccountService;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import tech.easyflow.common.constant.enums.EnumAccountType;
import tech.easyflow.common.constant.enums.EnumDataStatus;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.util.StringUtil;
import tech.easyflow.common.web.controller.BaseCurdController;
import tech.easyflow.common.web.jsonbody.JsonBody;
import tech.easyflow.log.annotation.LogRecord;
import tech.easyflow.system.entity.SysAccount;
import tech.easyflow.system.entity.vo.SysAccountImportResultVo;
import tech.easyflow.system.service.SysAccountService;
import tech.easyflow.system.util.SysPasswordPolicy;
import java.net.URLEncoder;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.Collection;
@@ -62,13 +67,21 @@ public class SysAccountController extends BaseCurdController<SysAccountService,
return Result.fail(1, "用户名已存在");
}
String password = entity.getPassword();
if (StringUtil.hasText(password)) {
entity.setPassword(BCrypt.hashpw(password));
if (!StringUtil.hasText(password)) {
return Result.fail(1, "密码不能为空");
}
SysPasswordPolicy.validateStrongPassword(password);
entity.setPassword(BCrypt.hashpw(password));
Integer status = entity.getStatus();
if (status == null) {
entity.setStatus(EnumDataStatus.AVAILABLE.getCode());
}
if (entity.getAccountType() == null) {
entity.setAccountType(EnumAccountType.NORMAL.getCode());
}
if (entity.getPasswordResetRequired() == null) {
entity.setPasswordResetRequired(false);
}
} else {
SysAccount record = service.getById(entity.getId());
// 如果修改了部门,就将用户踢下线,避免用户操作数据造成数据错误
@@ -149,15 +162,40 @@ public class SysAccountController extends BaseCurdController<SysAccountService,
if (!newPassword.equals(confirmPassword)) {
return Result.fail(2, "两次密码不一致");
}
SysPasswordPolicy.validateStrongPassword(newPassword);
SysAccount update = new SysAccount();
update.setId(loginAccountId);
update.setPassword(BCrypt.hashpw(newPassword));
update.setPasswordResetRequired(false);
update.setModified(new Date());
update.setModifiedBy(loginAccountId);
service.updateById(update);
return Result.ok();
}
@PostMapping("/resetPassword")
@SaCheckPermission("/api/v1/sysAccount/save")
public Result<Void> resetPassword(@JsonBody(value = "id", required = true) BigInteger id) {
service.resetPassword(id, SaTokenUtil.getLoginAccount().getId());
return Result.ok();
}
@PostMapping("/importExcel")
@SaCheckPermission("/api/v1/sysAccount/save")
public Result<SysAccountImportResultVo> importExcel(MultipartFile file) {
return Result.ok(service.importAccounts(file, SaTokenUtil.getLoginAccount()));
}
@GetMapping("/downloadImportTemplate")
@SaCheckPermission("/api/v1/sysAccount/query")
public void downloadImportTemplate(HttpServletResponse response) throws Exception {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("user_import_template", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
service.writeImportTemplate(response.getOutputStream());
}
@Override
@PostMapping("save")
public Result<?> save(@JsonBody SysAccount entity) {

View File

@@ -11,6 +11,7 @@ import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.jsonbody.JsonBody;
import tech.easyflow.system.entity.SysAccount;
import tech.easyflow.system.service.SysAccountService;
import tech.easyflow.system.util.SysPasswordPolicy;
import javax.annotation.Resource;
import java.math.BigInteger;
@@ -80,12 +81,14 @@ public class UcSysAccountController {
if (!newPassword.equals(confirmPassword)) {
return Result.fail(2, "两次密码不一致");
}
SysPasswordPolicy.validateStrongPassword(newPassword);
SysAccount update = new SysAccount();
update.setId(loginAccountId);
update.setPassword(BCrypt.hashpw(newPassword));
update.setPasswordResetRequired(false);
update.setModified(new Date());
update.setModifiedBy(loginAccountId);
service.updateById(update);
return Result.ok();
}
}
}