代码提交

This commit is contained in:
liang.chao 2025-10-14 17:44:23 +08:00
parent 6ae48554ca
commit b4e96a5835
10 changed files with 150 additions and 76 deletions

View File

@ -30,6 +30,7 @@ import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -370,22 +371,76 @@ public class FileManagementController extends BaseController {
return R.fail("文件未找到");
}
String filePath = uploadDir + record.getFilePath();
String fileName = record.getFileName();
// 直接使用字符串处理构建安全路径
String safeFullPath = buildSecureFullPath(uploadDir, record.getFilePath());
if (safeFullPath == null) {
return R.fail("无效的文件路径");
}
Path path = Paths.get(filePath);
File file = new File(safeFullPath);
if (!file.exists() || !file.isFile()) {
return R.fail("文件未找到");
}
// 2. 读取文件为字节数组
byte[] fileBytes = Files.readAllBytes(path);
try {
byte[] fileBytes = Files.readAllBytes(file.toPath());
String base64String = Base64.getEncoder().encodeToString(fileBytes);
// 3. 转为 Base64 编码字符串
String base64String = Base64.getEncoder().encodeToString(fileBytes);
response.put("fileName", record.getFileName());
response.put("suffix_name", record.getSuffixName());
response.put("fileBase64", base64String);
return R.ok(response);
} catch (IOException e) {
return R.fail("文件读取失败");
}
}
// 4. 设置响应数据
response.put("fileName", fileName);
response.put("suffix_name", record.getSuffixName());
// Base64 内容可直接用于前端
response.put("fileBase64", base64String);
return R.ok(response);
/**
* 构建安全的完整文件路径
*/
private String buildSecureFullPath(String baseDir, String filePath) {
if (StringUtils.isBlank(filePath)) {
return null;
}
// 统一路径分隔符
String unifiedPath = filePath.replace('\\', '/');
// 移除开头的斜杠
unifiedPath = unifiedPath.replaceAll("^/+", "");
// 检查路径遍历
if (unifiedPath.contains("../") || unifiedPath.contains("..\\")) {
return null;
}
// 检查绝对路径
if (unifiedPath.matches("^[a-zA-Z]:/.*") || unifiedPath.startsWith("/")) {
return null;
}
// 构建完整路径
String fullPath;
if (baseDir.endsWith(File.separator)) {
fullPath = baseDir + unifiedPath;
} else {
fullPath = baseDir + File.separator + unifiedPath;
}
// 使用File的getCanonicalPath进行最终验证
try {
File canonicalFile = new File(fullPath);
String canonicalPath = canonicalFile.getCanonicalPath();
// 验证是否仍在基础目录内
String canonicalBaseDir = new File(baseDir).getCanonicalPath();
if (!canonicalPath.startsWith(canonicalBaseDir)) {
return null;
}
return canonicalPath;
} catch (IOException e) {
return null;
}
}
}

View File

@ -4,17 +4,42 @@ import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.SM4;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author bonus
*/
@Component
public class Sm4Utils {
/**
* 必须是16字节
*/
private static final String KEY = "78d1295afa99449b99d6f83820e6965c";
@Value("${Sm4.KEY}")
private String key;
private static final String IV = "f555adf6c01d0ab0761e626a2dae34a2";
@Value("${Sm4.IV}")
private String iv;
private static String KEY;
private static String IV;
@PostConstruct
public void init() {
KEY = this.key;
IV = this.iv;
}
// 静态方法供外部使用
public static String getKey() {
return KEY;
}
public static String getIv() {
return IV;
}
/**
* 加密数据使用固定盐
*
@ -23,7 +48,9 @@ public class Sm4Utils {
*/
public static String encrypt(String plainText) {
try {
SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(KEY),HexUtil.decodeHex(IV));
SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(getKey()),HexUtil.decodeHex(getIv()));
System.out.println("key:"+getKey());
System.out.println("iv:"+getIv());
// 加密带盐的明文
byte[] encryptedData = sm4.encrypt(plainText);
// 返回带盐的加密结果Hex编码
@ -43,7 +70,7 @@ public class Sm4Utils {
public static String decrypt(String cipherText) {
try {
// 初始化SM4解密工具
SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(KEY),HexUtil.decodeHex(IV));
SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(getKey()),HexUtil.decodeHex(getIv()));
// 解密数据
byte[] decryptedData = sm4.decrypt(cipherText);
return new String(decryptedData);
@ -53,7 +80,7 @@ public class Sm4Utils {
}
// 测试方法演示加密和解密过程
public static void main(String[] args) {
/* public static void main(String[] args) {
String plainText = "15398187429";
System.out.println("原文: " + plainText);
@ -64,5 +91,5 @@ public class Sm4Utils {
// 解密密文
String decryptedText = Sm4Utils.decrypt(plainText);
System.out.println("解密后: " + decryptedText);
}
}*/
}

View File

@ -215,7 +215,8 @@ public class HttpUtils
try
{
log.info("sendSSLPost - {}", urlNameString);
SSLContext sc = SSLContext.getInstance("SSL");
// SSLContext sc = SSLContext.getInstance("SSL");
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
URL console = new URL(urlNameString);
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
@ -228,7 +229,7 @@ public class HttpUtils
conn.setDoInput(true);
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
conn.setHostnameVerifier(new SecureHostnameVerifier());
conn.connect();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
@ -282,12 +283,18 @@ public class HttpUtils
}
}
private static class TrustAnyHostnameVerifier implements HostnameVerifier
{
public static class SecureHostnameVerifier implements HostnameVerifier {
private final HostnameVerifier defaultVerifier;
public SecureHostnameVerifier() {
// 使用 JVM 默认的主机名验证器
this.defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
}
@Override
public boolean verify(String hostname, SSLSession session)
{
return true;
public boolean verify(String hostname, SSLSession session) {
// 使用标准的主机名验证
return defaultVerifier.verify(hostname, session);
}
}
}

View File

@ -159,7 +159,6 @@ public class RequestCoverFilter implements Filter {
if (integrality) {
String[] parts = requestBody.split("\\|");
if (parts.length != 2) {
log.error("解密后的请求体格式不正确: {}", requestBody);
throw new CaptchaException("请求参数不正确");
}
integrityVerification(parts[1], parts[0]);
@ -176,7 +175,6 @@ public class RequestCoverFilter implements Filter {
chain.doFilter(wrappedRequest, response);
} catch (Exception e) {
log.error("处理请求体时发生错误: {}", e.getMessage(), e);
throw new ServletException("请求处理失败", e);
}
}
@ -235,7 +233,6 @@ public class RequestCoverFilter implements Filter {
if (integrality) {
String[] parts = query.split("\\|");
if (parts.length != 2) {
log.error("解密后的参数格式不正确: {}", query);
throw new CaptchaException("请求参数不正确");
}
integrityVerification(parts[1], parts[0]);
@ -250,7 +247,6 @@ public class RequestCoverFilter implements Filter {
return new QueryStringRequestWrapper(request, query);
} catch (Exception e) {
log.error("解密查询参数时发生错误: {}", e.getMessage(), e);
throw new CaptchaException("请求参数不正确");
}
}
@ -488,7 +484,6 @@ public class RequestCoverFilter implements Filter {
if (integrality) {
String[] parts = decryptedParams.split("\\|");
if (parts.length != 2) {
log.error("解密后的参数格式不正确: {}", decryptedParams);
throw new CaptchaException("请求参数不正确");
}
integrityVerification(parts[1], parts[0]);
@ -505,7 +500,6 @@ public class RequestCoverFilter implements Filter {
}
} catch (Exception e) {
log.error("处理 multipart params 参数时发生错误: {}", e.getMessage(), e);
throw new CaptchaException("请求参数不正确");
}
}
@ -520,8 +514,8 @@ public class RequestCoverFilter implements Filter {
throw new CaptchaException("请求参数不正确");
}
String calculatedHash = Sm3Util.encrypt(data);
log.info("计算出的哈希值: {}", calculatedHash);
log.info("提供的哈希值: {}", providedHmac);
// log.info("计算出的哈希值: {}", calculatedHash);
// log.info("提供的哈希值: {}", providedHmac);
if (!calculatedHash.equals(providedHmac)) {
log.error("参数完整性校验失败");
throw new CaptchaException("请求参数不正确");

View File

@ -194,7 +194,7 @@ public class GenController extends BaseController {
/**
* 生成代码自定义路径
*/
@RequiresPermissions("tool:gen:code")
/* @RequiresPermissions("tool:gen:code")
@Log(title = "代码生成", businessType = BusinessType.GENCODE)
@GetMapping("/genCode/{tableName}")
public AjaxResult genCode(@PathVariable("tableName") String tableName) {
@ -203,7 +203,7 @@ public class GenController extends BaseController {
}
genTableService.generatorCode(tableName);
return success();
}
}*/
/**
* 同步数据库

View File

@ -2,6 +2,7 @@ package com.bonus.generator.mapper;
import java.util.List;
import com.bonus.generator.domain.GenTable;
import org.apache.ibatis.annotations.Param;
/**
* 业务 数据层
@ -87,5 +88,5 @@ public interface GenTableMapper
* @param sql 表结构
* @return 结果
*/
public int createTable(String sql);
public int createTable(@Param("sql") String sql);
}

View File

@ -172,7 +172,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</insert>
<update id="createTable">
${sql}
#{sql}
</update>
<update id="updateGenTable" parameterType="GenTable">

View File

@ -42,8 +42,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="status != null and status != ''">
AND status = #{status}
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
order by d.parent_id, d.order_num
</select>

View File

@ -51,8 +51,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(r.create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
order by r.role_sort
</select>

View File

@ -91,8 +91,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deptId != null and deptId != 0">
AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM da_ky_sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
</select>
<select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
@ -108,8 +106,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="phonenumber != null and phonenumber != ''">
AND INSTR(u.phonenumber, #{phonenumber}) > 0
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
</select>
<select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
@ -126,8 +122,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="phonenumber != null and phonenumber != ''">
AND INSTR(u.phonenumber, #{phonenumber}) > 0
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
</select>
<select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">