fix
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
common通用工具
|
||||
</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Spring框架基本的核心工具 -->
|
||||
@@ -156,6 +157,13 @@
|
||||
<version>1.6.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.ruoyi.common.utils;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PasswordValidator {
|
||||
|
||||
// 禁止使用的常见弱口令列表
|
||||
private static final String[] WEAK_PASSWORDS = {"123456@cxxm","123456", "password", "admin", "abc123", "qwerty"};
|
||||
|
||||
// 正则表达式模式
|
||||
private static final Pattern UPPERCASE_PATTERN = Pattern.compile("[A-Z]");
|
||||
private static final Pattern LOWERCASE_PATTERN = Pattern.compile("[a-z]");
|
||||
private static final Pattern DIGIT_PATTERN = Pattern.compile("[0-9]");
|
||||
private static final Pattern SPECIAL_CHAR_PATTERN = Pattern.compile("[!@#$%^&*()\\-_+=\\[\\]{}|;:,.<>/?]");
|
||||
|
||||
public static boolean isValidPasswordApi(String password){
|
||||
String userInfo =SecurityUtils.getUsername();
|
||||
// 检查是否为空或太短
|
||||
if (StringUtils.isEmpty(password) || password.length() < 8) {
|
||||
throw new RuntimeException("密码长度不能小于8位");
|
||||
}
|
||||
|
||||
// 检查是否包含用户信息
|
||||
if (StringUtils.isNotEmpty(userInfo) && password.toLowerCase().contains(userInfo.toLowerCase())) {
|
||||
throw new RuntimeException("密码不得包含用户信息");
|
||||
}
|
||||
|
||||
// 检查是否为常见弱口令
|
||||
for (String weakPassword : WEAK_PASSWORDS) {
|
||||
if (password.equals(weakPassword)) {
|
||||
throw new RuntimeException("密码不得包含常见弱口令");
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否包含重复字符或简单模式
|
||||
if (isSimplePattern(password)) {
|
||||
throw new RuntimeException("密码不得包含连续重复字符或简单模式");
|
||||
}
|
||||
|
||||
// 检查是否包含至少三种不同类型字符
|
||||
int charTypesCount = 0;
|
||||
if (UPPERCASE_PATTERN.matcher(password).find()) {
|
||||
charTypesCount++;
|
||||
}
|
||||
if (LOWERCASE_PATTERN.matcher(password).find()) {
|
||||
charTypesCount++;
|
||||
}
|
||||
if (DIGIT_PATTERN.matcher(password).find()) {
|
||||
charTypesCount++;
|
||||
}
|
||||
if (SPECIAL_CHAR_PATTERN.matcher(password).find()) {
|
||||
charTypesCount++;
|
||||
}
|
||||
if (charTypesCount < 3){
|
||||
throw new RuntimeException("密码必须包含至少三种不同类型字符");
|
||||
}
|
||||
return charTypesCount >= 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证密码强度
|
||||
*
|
||||
* @param password 待验证的密码
|
||||
* @param userInfo 用户信息,用于检查是否包含用户账号、姓名、工号、手机号、邮箱等
|
||||
* @return 如果密码强度足够则返回true,否则返回false
|
||||
*/
|
||||
public static boolean isValidPassword(String password, String userInfo){
|
||||
// 检查是否为空或太短
|
||||
if (StringUtils.isEmpty(password) || password.length() < 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否包含用户信息
|
||||
if (StringUtils.isNotEmpty(userInfo) && password.toLowerCase().contains(userInfo.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否为常见弱口令
|
||||
for (String weakPassword : WEAK_PASSWORDS) {
|
||||
if (password.equals(weakPassword)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否包含重复字符或简单模式
|
||||
if (isSimplePattern(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否包含至少三种不同类型字符
|
||||
int charTypesCount = 0;
|
||||
if (UPPERCASE_PATTERN.matcher(password).find()) {
|
||||
charTypesCount++;
|
||||
}
|
||||
if (LOWERCASE_PATTERN.matcher(password).find()) {
|
||||
charTypesCount++;
|
||||
}
|
||||
if (DIGIT_PATTERN.matcher(password).find()) {
|
||||
charTypesCount++;
|
||||
}
|
||||
if (SPECIAL_CHAR_PATTERN.matcher(password).find()) {
|
||||
charTypesCount++;
|
||||
}
|
||||
return charTypesCount >= 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查密码是否包含重复字符或简单模式
|
||||
*
|
||||
* @param password 待检查的密码
|
||||
* @return 如果包含重复字符或简单模式则返回true,否则返回false
|
||||
*/
|
||||
private static boolean isSimplePattern(String password) {
|
||||
// 检查简单模式(这里仅作为示例,您可以根据需要扩展)
|
||||
if (password.matches("(.)\\1{2}") || password.matches("\\d+") || password.matches("[a-zA-Z]+")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 测试密码校验
|
||||
String[] testPasswords = {"123456@cxxm", "abbbcd@@@", "StrongPasss1!", "A1b!2cD3", "123456", "password", "admin", "abc123", "qwerty"};
|
||||
String userInfo = "admin"; // 示例用户信息
|
||||
|
||||
for (String password : testPasswords) {
|
||||
System.out.println("Password: " + password + " is valid: " + isValidPassword(password, userInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,15 @@ import com.ruoyi.common.utils.StringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@Slf4j
|
||||
public class ResourceUtils {
|
||||
@@ -30,4 +37,77 @@ public class ResourceUtils {
|
||||
log.error("下载文件失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 多文件下载
|
||||
*
|
||||
* @param files
|
||||
* @param zipFile
|
||||
* @param response
|
||||
*/
|
||||
public static void multiDownload(List<File> files,
|
||||
File zipFile,
|
||||
HttpServletResponse response) {
|
||||
|
||||
|
||||
response.reset();
|
||||
// 设置response的Header
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
//Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存
|
||||
//attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"
|
||||
// filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
|
||||
try {
|
||||
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipFile.getName(), "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 告知浏览器文件的大小
|
||||
|
||||
//设置响应格式,已文件流的方式返回给前端。
|
||||
response.setContentType("application/octet-stream");
|
||||
//生成压缩文件
|
||||
ZipMultiFile(files, zipFile);
|
||||
response.addHeader("Content-Length", String.valueOf(zipFile.length()));
|
||||
|
||||
try (ServletOutputStream sos = response.getOutputStream();
|
||||
BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(zipFile.toPath()))) {
|
||||
byte[] buff = new byte[1024 * 10];
|
||||
int index;
|
||||
while ((index = bis.read(buff, 0, buff.length)) != -1) {
|
||||
sos.write(buff, 0, index);
|
||||
}
|
||||
sos.flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param files 需要压缩的文件列表
|
||||
* @param zipFile 压缩后的文件
|
||||
*/
|
||||
public static void ZipMultiFile(List<File> files, File zipFile) {
|
||||
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()))) {
|
||||
|
||||
for (File file : files) {
|
||||
try (FileInputStream fis = new FileInputStream(file);) {
|
||||
zipOut.putNextEntry(new ZipEntry(file.getName()));
|
||||
int temp;
|
||||
byte[] buf = new byte[1024];
|
||||
while ((temp = fis.read(buf)) != -1) {
|
||||
zipOut.write(buf, 0, temp);
|
||||
}
|
||||
zipOut.closeEntry();
|
||||
zipOut.flush();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user