fix: 优化密码重置逻辑

This commit is contained in:
tangwei 2026-04-29 11:19:09 +08:00
parent 70aeee3dc1
commit de0a291f70
6 changed files with 303 additions and 9 deletions

View File

@ -11,6 +11,7 @@ import com.yfd.platform.data.domain.ImportTask;
import com.yfd.platform.data.domain.BatchApproveRequest; import com.yfd.platform.data.domain.BatchApproveRequest;
import com.yfd.platform.data.domain.BatchRejectRequest; import com.yfd.platform.data.domain.BatchRejectRequest;
import com.yfd.platform.data.domain.vo.FishDraftDataVO; import com.yfd.platform.data.domain.vo.FishDraftDataVO;
import com.yfd.platform.data.service.AttachmentUploadService;
import com.yfd.platform.data.service.IFishDraftDataService; import com.yfd.platform.data.service.IFishDraftDataService;
import com.yfd.platform.data.service.IFishImportService; import com.yfd.platform.data.service.IFishImportService;
import com.yfd.platform.data.service.IImportTaskService; import com.yfd.platform.data.service.IImportTaskService;
@ -47,6 +48,9 @@ public class FishDraftDataController {
@Resource @Resource
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
@Resource
private AttachmentUploadService attachmentUploadService;
@PostMapping("/page") @PostMapping("/page")
@Operation(summary = "分页查询过鱼数据(关联电站和设施)") @Operation(summary = "分页查询过鱼数据(关联电站和设施)")
public ResponseResult queryPageList(@RequestBody DataSourceRequest dataSourceRequest) { public ResponseResult queryPageList(@RequestBody DataSourceRequest dataSourceRequest) {
@ -417,4 +421,22 @@ public class FishDraftDataController {
return ResponseResult.error("清理失败: " + e.getMessage()); return ResponseResult.error("清理失败: " + e.getMessage());
} }
} }
@PostMapping("/deleteAttachment")
@Operation(summary = "删除附件")
public ResponseResult deleteAttachment(@RequestParam String id,
@RequestHeader("token") String token) {
if (id == null || id.isEmpty()) {
return ResponseResult.error("附件ID不能为空");
}
if (token == null || token.isEmpty()) {
return ResponseResult.error("token不能为空");
}
boolean result = attachmentUploadService.deleteFile(id, token);
if (result) {
return ResponseResult.success("删除成功");
} else {
return ResponseResult.error("删除失败");
}
}
} }

View File

@ -260,4 +260,65 @@ public class AttachmentUploadService {
return null; return null;
} }
} }
private static final String DELETE_URL = "https://211.99.26.225:12125/delete";
public boolean deleteFile(String attachmentId, String token) {
if (attachmentId == null || attachmentId.isEmpty()) {
log.warn("附件ID为空");
return false;
}
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}
};
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpClient secureClient = HttpClient.newBuilder()
.sslContext(sc)
.build();
String formData = "id=" + attachmentId;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(DELETE_URL))
.header("Content-Type", "application/x-www-form-urlencoded")
.header("token", token)
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpResponse<String> response = secureClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
String responseBody = response.body();
return parseDeleteResult(responseBody);
} else {
log.error("删除附件失败: {}, 状态码: {}", attachmentId, response.statusCode());
return false;
}
} catch (Exception e) {
log.error("删除附件过程中发生异常: {}", attachmentId, e);
return false;
}
}
private boolean parseDeleteResult(String jsonResponse) {
if (jsonResponse == null || jsonResponse.isEmpty()) {
return false;
}
try {
JSONObject json = JSONObject.parseObject(jsonResponse);
return json.containsKey("success") && json.getBoolean("success");
} catch (Exception e) {
log.error("解析删除结果失败: {}", jsonResponse, e);
return false;
}
}
} }

View File

@ -62,7 +62,7 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
* userid 用户id * userid 用户id
* 返回值说明: * 返回值说明:
************************************/ ************************************/
String getMaxLevel(@Param("userid") String userid); String getMaxLevel(@Param("userId") String userId);
/*********************************** /***********************************
* 用途说明根据用户id删除所分配的角色 * 用途说明根据用户id删除所分配的角色

View File

@ -17,6 +17,7 @@ import com.yfd.platform.system.mapper.SysRoleMapper;
import com.yfd.platform.system.mapper.SysUserMapper; import com.yfd.platform.system.mapper.SysUserMapper;
import com.yfd.platform.system.service.IUserService; import com.yfd.platform.system.service.IUserService;
import com.yfd.platform.utils.FileUtil; import com.yfd.platform.utils.FileUtil;
import com.yfd.platform.utils.PasswordGenerator;
import com.yfd.platform.utils.SecurityUtils; import com.yfd.platform.utils.SecurityUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import com.yfd.platform.config.FileSpaceProperties; import com.yfd.platform.config.FileSpaceProperties;
@ -429,12 +430,14 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
//根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id
String level = sysUserMapper.getMaxLevel(id); String level = sysUserMapper.getMaxLevel(id);
//判断是否获取级别 //判断是否获取级别
if (StrUtil.isNotEmpty(level)) { if ("admin".equals(SecurityUtils.getCurrentUsername())||StrUtil.isNotEmpty(level)) {
//判断当前用户级别 管理员及以上权限 //判断当前用户级别 管理员及以上权限
if (Integer.parseInt(level) <= 2) { if ("admin".equals(SecurityUtils.getCurrentUsername())||Integer.parseInt(level) <= 2) {
SysUser sysUser = sysUserMapper.selectById(id);
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>(); UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
String password = PasswordGenerator.generateRandomPassword(sysUser.getUsername());
//根据id 修改密码密码修改时间最近修改者最近修改日期 将密码修改为 123456 //根据id 修改密码密码修改时间最近修改者最近修改日期 将密码修改为 123456
String cryptPassword = passwordEncoder.encode("123456"); String cryptPassword = passwordEncoder.encode(password);
updateWrapper.eq("id", id).set("password", cryptPassword).set( updateWrapper.eq("id", id).set("password", cryptPassword).set(
"pwdresettime", "pwdresettime",
new Timestamp(System.currentTimeMillis())).set( new Timestamp(System.currentTimeMillis())).set(
@ -443,7 +446,7 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
"lastmodifier", getUsername()); "lastmodifier", getUsername());
//是否修改成功 //是否修改成功
this.update(updateWrapper); this.update(updateWrapper);
return ResponseResult.success("重置密码成功"); return ResponseResult.successData(password);
} }
} }
return ResponseResult.error(); return ResponseResult.error();
@ -462,7 +465,7 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
//根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id
String level = sysUserMapper.getMaxLevel(id); String level = sysUserMapper.getMaxLevel(id);
//判断当前用户级别 管理员及以上权限 //判断当前用户级别 管理员及以上权限
if (Integer.parseInt(level) <= 2) { if ("admin".equals(SecurityUtils.getCurrentUsername())||Integer.parseInt(level) <= 2) {
UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>(); UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
//根据id修改用户状态最近修改人最近修改时间 //根据id修改用户状态最近修改人最近修改时间
updateWrapper.eq("id", id).set("status", status).set( updateWrapper.eq("id", id).set("status", status).set(

View File

@ -0,0 +1,205 @@
package com.yfd.platform.utils;
import java.security.SecureRandom;
/**
* 随机密码生成器满足以下规则
* 1. 必须包含大写字母小写字母数字特殊字符中的至少三类
* 2. 不能包含2位及以上相同字符的连续重复如11aa
* 3. 不能包含2位及以上连续递增或递减的数字如1221
* 4. 不能包含2位及以上连续递增或递减的字母如abba忽略大小写
* 5. 不能包含用户名忽略大小写
* 6. 密码的字母部分不能是用户名的子串忽略大小写连续子串
* 7. 密码不能与用户名存在明显关联字母部分不能等于用户名或其反转
* 8. 密码开头和结尾不能是特殊字符
* 9. 密码长度可配置默认10-12位
*/
public class PasswordGenerator {
private static final String LOWERS = "abcdefghijklmnopqrstuvwxyz";
private static final String UPPERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String DIGITS = "0123456789";
private static final String SPECIALS = "!@#$%^&*()_+-=[]{}|;:,.<>?";
private static final SecureRandom RANDOM = new SecureRandom();
private static final int DEFAULT_MIN_LEN = 10;
private static final int DEFAULT_MAX_LEN = 12;
private static final int MAX_ATTEMPTS = 100;
private static int minLength = DEFAULT_MIN_LEN;
private static int maxLength = DEFAULT_MAX_LEN;
public static void configure(int minLen, int maxLen) {
if (minLen < 6) {
minLen = 6;
}
if (maxLen > 32) {
maxLen = 32;
}
if (minLen > maxLen) {
minLen = maxLen;
}
minLength = minLen;
maxLength = maxLen;
}
public static String generateRandomPassword(String username) {
return generateRandomPassword(username, minLength, maxLength);
}
public static String generateRandomPassword(String username, int minLen, int maxLen) {
int configuredMin = minLen > 0 ? minLen : DEFAULT_MIN_LEN;
int configuredMax = maxLen > 0 ? maxLen : DEFAULT_MAX_LEN;
if (configuredMin > configuredMax) {
configuredMin = configuredMax;
}
for (int attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
int length = configuredMin + RANDOM.nextInt(configuredMax - configuredMin + 1);
String candidate = generateRandomString(length);
if (isValidPassword(candidate, username)) {
return candidate;
}
}
throw new RuntimeException("Unable to generate a valid password after " + MAX_ATTEMPTS + " attempts");
}
private static String generateRandomString(int length) {
String lowerChars = LOWERS;
String upperChars = UPPERS;
String digitChars = DIGITS;
String specialChars = SPECIALS;
StringBuilder sb = new StringBuilder(length);
int firstCharIdx = RANDOM.nextInt(lowerChars.length() + upperChars.length() + digitChars.length());
String firstPool = lowerChars + upperChars + digitChars;
sb.append(firstPool.charAt(firstCharIdx));
for (int i = 1; i < length - 1; i++) {
int choice = RANDOM.nextInt(100);
String charsToUse;
if (choice < 25) {
charsToUse = specialChars;
} else if (choice < 55) {
charsToUse = lowerChars;
} else if (choice < 80) {
charsToUse = upperChars;
} else {
charsToUse = digitChars;
}
int idx = RANDOM.nextInt(charsToUse.length());
sb.append(charsToUse.charAt(idx));
}
int lastCharIdx = RANDOM.nextInt(lowerChars.length() + upperChars.length() + digitChars.length());
String lastPool = lowerChars + upperChars + digitChars;
sb.append(lastPool.charAt(lastCharIdx));
return sb.toString();
}
private static boolean isValidPassword(String password, String username) {
if (password == null || password.length() < minLength) return false;
if (!hasEnoughCategories(password)) return false;
if (hasConsecutiveRepeats(password)) return false;
if (hasSequentialDigits(password)) return false;
if (hasSequentialLetters(password)) return false;
if (!isNormalChar(password.charAt(0))) return false;
if (!isNormalChar(password.charAt(password.length() - 1))) return false;
if (username != null && !username.isEmpty()) {
if (containsIgnoreCase(password, username)) return false;
String lettersOnly = extractLetters(password);
if (containsIgnoreCase(lettersOnly, username)) return false;
if (isObviousRelation(lettersOnly, username)) return false;
}
return true;
}
private static boolean isNormalChar(char c) {
return Character.isLowerCase(c) || Character.isUpperCase(c) || Character.isDigit(c);
}
private static boolean hasEnoughCategories(String s) {
boolean hasLower = false, hasUpper = false, hasDigit = false, hasSpecial = false;
for (char c : s.toCharArray()) {
if (Character.isLowerCase(c)) hasLower = true;
else if (Character.isUpperCase(c)) hasUpper = true;
else if (Character.isDigit(c)) hasDigit = true;
else hasSpecial = true;
}
int cnt = (hasLower ? 1 : 0) + (hasUpper ? 1 : 0) + (hasDigit ? 1 : 0) + (hasSpecial ? 1 : 0);
return cnt >= 3;
}
private static boolean hasConsecutiveRepeats(String s) {
for (int i = 0; i < s.length() - 1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) return true;
}
return false;
}
private static boolean hasSequentialDigits(String s) {
for (int i = 0; i < s.length() - 1; i++) {
char c1 = s.charAt(i);
char c2 = s.charAt(i + 1);
if (Character.isDigit(c1) && Character.isDigit(c2)) {
int diff = c2 - c1;
if (Math.abs(diff) == 1) return true;
}
}
return false;
}
private static boolean hasSequentialLetters(String s) {
for (int i = 0; i < s.length() - 1; i++) {
char c1 = s.charAt(i);
char c2 = s.charAt(i + 1);
if (Character.isLetter(c1) && Character.isLetter(c2)) {
char low1 = Character.toLowerCase(c1);
char low2 = Character.toLowerCase(c2);
int diff = low2 - low1;
if (Math.abs(diff) == 1) return true;
}
}
return false;
}
private static boolean containsIgnoreCase(String str, String search) {
if (str == null || search == null) return false;
return str.toLowerCase().contains(search.toLowerCase());
}
private static String extractLetters(String s) {
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
if (Character.isLetter(c)) sb.append(c);
}
return sb.toString();
}
private static boolean isObviousRelation(String lettersOnly, String username) {
String lowerLetters = lettersOnly.toLowerCase();
String lowerUser = username.toLowerCase();
if (lowerLetters.equals(lowerUser)) return true;
String reversedUser = new StringBuilder(lowerUser).reverse().toString();
return lowerLetters.equals(reversedUser);
}
public static void main(String[] args) {
configure(10, 12);
String username = "admin";
String resetPwd = generateRandomPassword(username);
System.out.println("Generated password: " + resetPwd);
System.out.println("Password length: " + resetPwd.length());
System.out.println("First char: '" + resetPwd.charAt(0) + "' (is special: " + !isNormalChar(resetPwd.charAt(0)) + ")");
System.out.println("Last char: '" + resetPwd.charAt(resetPwd.length() - 1) + "' (is special: " + !isNormalChar(resetPwd.charAt(resetPwd.length() - 1)) + ")");
configure(8, 16);
System.out.println("\nAfter configure(8, 16):");
resetPwd = generateRandomPassword(username);
System.out.println("Generated password: " + resetPwd);
System.out.println("Password length: " + resetPwd.length());
}
}

View File

@ -49,9 +49,12 @@
<!--根据用户表 id 查询角色表最大级别--> <!--根据用户表 id 查询角色表最大级别-->
<select id="getMaxLevel" resultType="String"> <select id="getMaxLevel" resultType="String">
SELECT MIN(r."LEVEL") SELECT MIN(TO_NUMBER(t.level_col))
FROM (
SELECT r."LEVEL" AS level_col
FROM sys_role r FROM sys_role r
WHERE r.id IN ( SELECT roleid FROM sys_role_users WHERE userid = #{userId} ) WHERE r.id IN (SELECT roleid FROM sys_role_users WHERE userid = #{userId})
) t
</select> </select>
<select id="queryUsers" resultType="com.yfd.platform.system.domain.SysUser"> <select id="queryUsers" resultType="com.yfd.platform.system.domain.SysUser">
SELECT DISTINCT SELECT DISTINCT