From de0a291f700484089fbcaf78315bb1e0cb759d2e Mon Sep 17 00:00:00 2001 From: tangwei Date: Wed, 29 Apr 2026 11:19:09 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E9=87=8D=E7=BD=AE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FishDraftDataController.java | 22 ++ .../data/service/AttachmentUploadService.java | 61 ++++++ .../platform/system/mapper/SysUserMapper.java | 2 +- .../system/service/impl/UserServiceImpl.java | 13 +- .../yfd/platform/utils/PasswordGenerator.java | 205 ++++++++++++++++++ .../resources/mapper/system/SysUserMapper.xml | 9 +- 6 files changed, 303 insertions(+), 9 deletions(-) create mode 100644 backend/src/main/java/com/yfd/platform/utils/PasswordGenerator.java diff --git a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java index cf2b1d4..03ff9bb 100644 --- a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java +++ b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java @@ -11,6 +11,7 @@ import com.yfd.platform.data.domain.ImportTask; import com.yfd.platform.data.domain.BatchApproveRequest; import com.yfd.platform.data.domain.BatchRejectRequest; 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.IFishImportService; import com.yfd.platform.data.service.IImportTaskService; @@ -47,6 +48,9 @@ public class FishDraftDataController { @Resource private ObjectMapper objectMapper; + @Resource + private AttachmentUploadService attachmentUploadService; + @PostMapping("/page") @Operation(summary = "分页查询过鱼数据(关联电站和设施)") public ResponseResult queryPageList(@RequestBody DataSourceRequest dataSourceRequest) { @@ -417,4 +421,22 @@ public class FishDraftDataController { 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("删除失败"); + } + } } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java b/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java index 146d18a..5b50d41 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java +++ b/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java @@ -260,4 +260,65 @@ public class AttachmentUploadService { 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 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; + } + } } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java index 7aae6a3..f031cf8 100644 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java +++ b/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java @@ -62,7 +62,7 @@ public interface SysUserMapper extends BaseMapper { * userid 用户id * 返回值说明: ************************************/ - String getMaxLevel(@Param("userid") String userid); + String getMaxLevel(@Param("userId") String userId); /*********************************** * 用途说明:根据用户id删除所分配的角色 diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java index 063d93b..e2bc0c9 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java @@ -17,6 +17,7 @@ import com.yfd.platform.system.mapper.SysRoleMapper; import com.yfd.platform.system.mapper.SysUserMapper; import com.yfd.platform.system.service.IUserService; import com.yfd.platform.utils.FileUtil; +import com.yfd.platform.utils.PasswordGenerator; import com.yfd.platform.utils.SecurityUtils; import lombok.RequiredArgsConstructor; import com.yfd.platform.config.FileSpaceProperties; @@ -429,12 +430,14 @@ public class UserServiceImpl extends ServiceImpl impleme //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户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 updateWrapper = new UpdateWrapper<>(); + String password = PasswordGenerator.generateRandomPassword(sysUser.getUsername()); //根据id 修改密码,密码修改时间,最近修改者,最近修改日期 将密码修改为 123456 - String cryptPassword = passwordEncoder.encode("123456"); + String cryptPassword = passwordEncoder.encode(password); updateWrapper.eq("id", id).set("password", cryptPassword).set( "pwdresettime", new Timestamp(System.currentTimeMillis())).set( @@ -443,7 +446,7 @@ public class UserServiceImpl extends ServiceImpl impleme "lastmodifier", getUsername()); //是否修改成功 this.update(updateWrapper); - return ResponseResult.success("重置密码成功"); + return ResponseResult.successData(password); } } return ResponseResult.error(); @@ -462,7 +465,7 @@ public class UserServiceImpl extends ServiceImpl impleme //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id String level = sysUserMapper.getMaxLevel(id); //判断当前用户级别 管理员及以上权限 - if (Integer.parseInt(level) <= 2) { + if ("admin".equals(SecurityUtils.getCurrentUsername())||Integer.parseInt(level) <= 2) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); //根据id修改用户状态,最近修改人,最近修改时间 updateWrapper.eq("id", id).set("status", status).set( diff --git a/backend/src/main/java/com/yfd/platform/utils/PasswordGenerator.java b/backend/src/main/java/com/yfd/platform/utils/PasswordGenerator.java new file mode 100644 index 0000000..0f910c7 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/utils/PasswordGenerator.java @@ -0,0 +1,205 @@ +package com.yfd.platform.utils; + +import java.security.SecureRandom; + +/** + * 随机密码生成器,满足以下规则: + * 1. 必须包含大写字母、小写字母、数字、特殊字符中的至少三类 + * 2. 不能包含2位及以上相同字符的连续重复(如11、aa) + * 3. 不能包含2位及以上连续递增或递减的数字(如12、21) + * 4. 不能包含2位及以上连续递增或递减的字母(如ab、ba,忽略大小写) + * 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()); + } +} \ No newline at end of file diff --git a/backend/src/main/resources/mapper/system/SysUserMapper.xml b/backend/src/main/resources/mapper/system/SysUserMapper.xml index 70ac49a..1ee549f 100644 --- a/backend/src/main/resources/mapper/system/SysUserMapper.xml +++ b/backend/src/main/resources/mapper/system/SysUserMapper.xml @@ -49,9 +49,12 @@