日常事务-处分管理 添加印章图片签名验证功能

- 实现了图片签名工具类ImageSignUtils,支持生成和验证带时间戳的签名URL
- 配置SecurityConfig允许匿名访问签名的印章图片URL,但Base64接口需认证
- 创建StampController提供受保护的印章图片访问接口
- 将应用默认文件路径配置改为Windows环境路径
- 支持通过签名URL安全访问印章图片资源
This commit is contained in:
2026-03-20 11:48:37 +08:00
parent e43637894b
commit f99b4621d2
4 changed files with 183 additions and 1 deletions

View File

@@ -0,0 +1,100 @@
package com.srs.common.utils.sign;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
/**
* 图片签名工具类
* 用于生成和验证图片访问签名URL
*/
public class ImageSignUtils {
private static final String SECRET_KEY = "srs-stamp-secret-key-2024";
private static final long DEFAULT_EXPIRE_TIME = 3 * 60_000; // 3分钟
/**
* 生成签名
*/
public static String generateSign(String fileName, long expireTime) {
String raw = fileName + "-" + expireTime + "-" + SECRET_KEY;
return md5(raw);
}
/**
* 生成带签名的URL
*/
public static String generateSignedUrl(String fileName) {
long expireTime = System.currentTimeMillis() + DEFAULT_EXPIRE_TIME;
String sign = generateSign(fileName, expireTime);
return String.format("/common/stamp/%s?expire=%d&sign=%s",
encodeFileName(fileName), expireTime, sign);
}
/**
* 验证签名是否有效
*/
public static boolean validateSign(String fileName, long expireTime, String sign) {
if (System.currentTimeMillis() > expireTime) {
return false; // 已过期
}
String expectedSign = generateSign(fileName, expireTime);
return expectedSign.equals(sign);
}
/**
* 从请求中提取文件名
*/
public static String extractFileName(HttpServletRequest request) {
String uri = request.getRequestURI();
String fileName = uri.substring(uri.lastIndexOf("/common/stamp/") + 14);
int paramIndex = fileName.indexOf("?");
if (paramIndex > 0) {
fileName = fileName.substring(0, paramIndex);
}
return decodeFileName(fileName);
}
/**
* 验证请求签名
*/
public static boolean validateRequest(HttpServletRequest request) {
String fileName = extractFileName(request);
String expireStr = request.getParameter("expire");
String sign = request.getParameter("sign");
if (fileName == null || expireStr == null || sign == null) {
return false;
}
try {
long expireTime = Long.parseLong(expireStr);
return validateSign(fileName, expireTime, sign);
} catch (NumberFormatException e) {
return false;
}
}
private static String encodeFileName(String fileName) {
return Base64.getUrlEncoder().encodeToString(fileName.getBytes(StandardCharsets.UTF_8));
}
private static String decodeFileName(String encoded) {
return new String(Base64.getUrlDecoder().decode(encoded), StandardCharsets.UTF_8);
}
private static String md5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (Exception e) {
throw new RuntimeException("MD5 calculation failed", e);
}
}
}