fix: 优化密码重置逻辑
This commit is contained in:
parent
70aeee3dc1
commit
de0a291f70
@ -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("删除失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -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删除所分配的角色
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user