From 294dcb1994e035e234169dd885ab501592547a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=9B=84?= Date: Fri, 21 Jul 2023 09:52:27 +0000 Subject: [PATCH] =?UTF-8?q?!170=20=E5=88=A0=E9=99=A4=E5=8A=9F=E8=83=BD=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=AA=8C=E8=AF=81=E7=A0=81=E6=96=B9=E6=B3=95?= =?UTF-8?q?=20=E5=88=A0=E9=99=A4=E5=8A=9F=E8=83=BD=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E7=A0=81=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/main/config/application.properties | 2 + .../cn/keking/config/ConfigConstants.java | 18 +++- .../keking/config/ConfigRefreshComponent.java | 3 + .../keking/utils/RandomValidateCodeUtil.java | 90 +++++++++++++++++++ .../keking/web/controller/FileController.java | 23 ++++- .../controller/OnlinePreviewController.java | 86 ++++++++++++++++++ .../keking/web/filter/AttributeSetFilter.java | 1 + server/src/main/resources/web/main/index.ftl | 50 +++++++++++ 8 files changed, 266 insertions(+), 7 deletions(-) create mode 100644 server/src/main/java/cn/keking/utils/RandomValidateCodeUtil.java diff --git a/server/src/main/config/application.properties b/server/src/main/config/application.properties index 8566cb84..1eee1ef7 100644 --- a/server/src/main/config/application.properties +++ b/server/src/main/config/application.properties @@ -130,6 +130,8 @@ tif.preview.type = ${KK_TIF_PREVIEW_TYPE:tif} beian = ${KK_BEIAN:default} #禁止上传类型 prohibit = ${KK_PROHIBIT:exe,dll,dat} +#启用验证码删除文件 默认关闭 +delete.captcha= ${KK_DELETE_CAPTCHA:false} #删除密码 delete.password = ${KK_DELETE_PASSWORD:123456} #删除 转换后OFFICE、CAD、TIFF、压缩包源文件 默认开启 节约磁盘空间 diff --git a/server/src/main/java/cn/keking/config/ConfigConstants.java b/server/src/main/java/cn/keking/config/ConfigConstants.java index 46401596..be189281 100644 --- a/server/src/main/java/cn/keking/config/ConfigConstants.java +++ b/server/src/main/java/cn/keking/config/ConfigConstants.java @@ -50,6 +50,7 @@ public class ConfigConstants { private static String officeTypeWeb; private static String cadPreviewType; private static Boolean deleteSourceFile; + private static Boolean deleteCaptcha; public static final String DEFAULT_CACHE_ENABLED = "true"; public static final String DEFAULT_TXT_TYPE = "txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd"; @@ -78,6 +79,7 @@ public class ConfigConstants { public static final String DEFAULT_PDF2_JPG_DPI = "105"; public static final String DEFAULT_OFFICE_TYPE_WEB = "web"; public static final String DEFAULT_DELETE_SOURCE_FILE = "true"; + public static final String DEFAULT_DELETE_CAPTCHA = "false"; public static Boolean isCacheEnabled() { return cacheEnabled; @@ -447,7 +449,9 @@ public class ConfigConstants { setDeleteSourceFileValue(deleteSourceFile); } - + public static void setDeleteSourceFileValue(Boolean deleteSourceFile) { + ConfigConstants.deleteSourceFile = deleteSourceFile; + } public static String getCadPreviewType() { return cadPreviewType; @@ -462,8 +466,16 @@ public class ConfigConstants { ConfigConstants.cadPreviewType = cadPreviewType; } - public static void setDeleteSourceFileValue(Boolean deleteSourceFile) { - ConfigConstants.deleteSourceFile = deleteSourceFile; + public static Boolean getDeleteCaptcha() { + return deleteCaptcha; } + @Value("${delete.captcha:false}") + public void setDeleteCaptcha(Boolean deleteCaptcha) { + setDeleteCaptchaValue(deleteCaptcha); + } + + public static void setDeleteCaptchaValue(Boolean deleteCaptcha) { + ConfigConstants.deleteCaptcha = deleteCaptcha; + } } diff --git a/server/src/main/java/cn/keking/config/ConfigRefreshComponent.java b/server/src/main/java/cn/keking/config/ConfigRefreshComponent.java index b1337320..26cc4c7e 100644 --- a/server/src/main/java/cn/keking/config/ConfigRefreshComponent.java +++ b/server/src/main/java/cn/keking/config/ConfigRefreshComponent.java @@ -62,6 +62,7 @@ public class ConfigRefreshComponent { String officeTypeWeb; String cadPreviewType; boolean deleteSourceFile; + boolean deleteCaptcha; while (true) { FileReader fileReader = new FileReader(configFilePath); BufferedReader bufferedReader = new BufferedReader(fileReader); @@ -94,6 +95,7 @@ public class ConfigRefreshComponent { pdf2JpgDpi = Integer.parseInt(properties.getProperty("pdf2jpg.dpi", ConfigConstants.DEFAULT_PDF2_JPG_DPI)); officeTypeWeb = properties.getProperty("office.type.web", ConfigConstants.DEFAULT_OFFICE_TYPE_WEB); deleteSourceFile = Boolean.parseBoolean(properties.getProperty("delete.source.file", ConfigConstants.DEFAULT_DELETE_SOURCE_FILE)); + deleteCaptcha = Boolean.parseBoolean(properties.getProperty("delete.captcha", ConfigConstants.DEFAULT_DELETE_CAPTCHA)); prohibitArray = prohibit.split(","); ConfigConstants.setCacheEnabledValueValue(cacheEnabled); @@ -121,6 +123,7 @@ public class ConfigRefreshComponent { ConfigConstants.setPdf2JpgDpiValue(pdf2JpgDpi); ConfigConstants.setOfficeTypeWebValue(officeTypeWeb); ConfigConstants.setDeleteSourceFileValue(deleteSourceFile); + ConfigConstants.setDeleteCaptchaValue(deleteCaptcha); setWatermarkConfig(properties); bufferedReader.close(); fileReader.close(); diff --git a/server/src/main/java/cn/keking/utils/RandomValidateCodeUtil.java b/server/src/main/java/cn/keking/utils/RandomValidateCodeUtil.java new file mode 100644 index 00000000..2b9c5827 --- /dev/null +++ b/server/src/main/java/cn/keking/utils/RandomValidateCodeUtil.java @@ -0,0 +1,90 @@ +package cn.keking.utils; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +public class RandomValidateCodeUtil { + + private static final int width = 100;// 定义图片的width + private static final int height = 30;// 定义图片的height + private static final int codeCount = 4;// 定义图片上显示验证码的个数 + private static final int xx = 18; + private static final int fontHeight = 28; + private static final int codeY = 27; + private static final char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R','T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a','b','c','d','e','f','g','h','j','k','m','n','p','q','r','s','t','u','v','w','x','y', '2', '3', '4','5', '6', '7', '8', '9' }; + + /** + * 生成一个map集合 + * code为生成的验证码 + * codePic为生成的验证码BufferedImage对象 + */ + public static Map generateCodeAndPic(String ip, String sessionCode, int lx) { + // 定义图像buffer + BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + // Graphics2D gd = buffImg.createGraphics(); + // Graphics2D gd = (Graphics2D) buffImg.getGraphics(); + Graphics gd = buffImg.getGraphics(); + // 创建一个随机数生成器类 + Random random = new Random(); + // 将图像填充为白色 + gd.setColor(Color.WHITE); + gd.fillRect(0, 0, width, height); + + // 创建字体,字体的大小应该根据图片的高度来定。 + Font font = new Font("Times New Roman", Font.BOLD, fontHeight); + // 设置字体。 + gd.setFont(font); + + // 画边框。 + gd.setColor(Color.BLACK); + gd.drawRect(0, 0, width - 1, height - 1); + + // 随机产生40条干扰线,使图象中的认证码不易被其它程序探测到。 + gd.setColor(Color.BLACK); + for (int i = 0; i < 30; i++) { + int x = random.nextInt(width); + int y = random.nextInt(height); + int xl = random.nextInt(12); + int yl = random.nextInt(12); + gd.drawLine(x, y, x + xl, y + yl); + } + StringBuffer randomCode = new StringBuffer(); + Map map = new HashMap<>(); + // randomCode用于保存随机产生的验证码,以便用户登录后进行验证。 + int red, green, blue; + if (lx ==1){ + // 产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同。 + red = random.nextInt(255); + green = random.nextInt(255); + blue = random.nextInt(255); + // 用随机产生的颜色将验证码绘制到图像中。 + gd.setColor(new Color(red, green, blue)); + gd.drawString(sessionCode, xx, codeY); + randomCode.append(sessionCode); + }else { + // 随机产生codeCount数字的验证码。 + for (int i = 0; i < codeCount; i++) { + // 得到随机产生的验证码数字。 + String code = String.valueOf(codeSequence[random.nextInt(30)]); + // 产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同。 + red = random.nextInt(255); + green = random.nextInt(255); + blue = random.nextInt(255); + // 用随机产生的颜色将验证码绘制到图像中。 + gd.setColor(new Color(red, green, blue)); + gd.drawString(code, (i + 1) * xx, codeY); + // 将产生的四个随机数组合在一起。 + randomCode.append(code); + } + } + //存放验证码 + map.put("code", randomCode); + //存放生成的验证码BufferedImage对象 + map.put("codePic", buffImg); + return map; + } +} diff --git a/server/src/main/java/cn/keking/web/controller/FileController.java b/server/src/main/java/cn/keking/web/controller/FileController.java index 28fabbec..3510eef1 100644 --- a/server/src/main/java/cn/keking/web/controller/FileController.java +++ b/server/src/main/java/cn/keking/web/controller/FileController.java @@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -59,15 +60,28 @@ public class FileController { } @GetMapping("/deleteFile") - public ReturnResponse deleteFile(String fileName,String password) { + public ReturnResponse deleteFile(HttpServletRequest request, String fileName, String password) { ReturnResponse checkResult = this.deleteFileCheck(fileName); if (checkResult.isFailure()) { return checkResult; } fileName = checkResult.getContent().toString(); - if(!ConfigConstants.getPassword().equalsIgnoreCase(password)) { - logger.error("删除文件【{}】失败,密码错误!",fileName); - return ReturnResponse.failure("删除文件失败,密码错误!"); + if(ConfigConstants.getDeleteCaptcha()){ + String sessionCode; + try { + sessionCode = request.getSession().getAttribute("code").toString(); //获取已经保存的验证码 + } catch (Exception e) { + sessionCode = "null"; + } + if (password==null || !sessionCode.equalsIgnoreCase(password)){ + logger.error("删除文件【{}】失败,密码错误!",fileName); + return ReturnResponse.failure("删除文件失败,密码错误!"); + } + }else { + if(password==null || !ConfigConstants.getPassword().equalsIgnoreCase(password)) { + logger.error("删除文件【{}】失败,密码错误!",fileName); + return ReturnResponse.failure("删除文件失败,密码错误!"); + } } File file = new File(fileDir + demoPath + fileName); logger.info("删除文件:{}", file.getAbsolutePath()); @@ -76,6 +90,7 @@ public class FileController { logger.error(msg); return ReturnResponse.failure(msg); } + request.getSession().removeAttribute("code"); //删除缓存验证码 return ReturnResponse.success(); } diff --git a/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java b/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java index ed29684a..cb15ba10 100644 --- a/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java +++ b/server/src/main/java/cn/keking/web/controller/OnlinePreviewController.java @@ -1,5 +1,6 @@ package cn.keking.web.controller; +import cn.keking.config.ConfigConstants; import cn.keking.model.FileAttribute; import cn.keking.service.FileHandlerService; import cn.keking.service.FilePreview; @@ -7,6 +8,7 @@ import cn.keking.service.FilePreviewFactory; import cn.keking.service.cache.CacheService; import cn.keking.service.impl.OtherFilePreviewImpl; import cn.keking.utils.KkFileUtils; +import cn.keking.utils.RandomValidateCodeUtil; import cn.keking.utils.WebUtils; import fr.opensagres.xdocreport.core.io.IOUtils; import io.mola.galimatias.GalimatiasParseException; @@ -15,18 +17,26 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; +import javax.imageio.ImageIO; +import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.awt.image.RenderedImage; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.text.SimpleDateFormat; import java.util.Arrays; +import java.util.Date; import java.util.List; +import java.util.Map; import static cn.keking.service.FilePreview.PICTURE_FILE_PREVIEW_PAGE; @@ -160,6 +170,82 @@ public class OnlinePreviewController { } } } + /** + * 验证码方法 + */ + @RequestMapping("/captcha") + public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception { + if(!ConfigConstants.getDeleteCaptcha()){ + return; + } + response.setContentType("image/gif"); + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setDateHeader("Expires", 0); + Date date = new Date(); // 当前时间 + SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 设置时间格式 + String sessionCode; + try { + sessionCode = request.getSession().getAttribute("code").toString(); //获取已经保存的验证码 + } catch (Exception e) { + sessionCode= null; + } + Object time = request.getSession().getAttribute("time"); //获取已经保存的时间 + if (ObjectUtils.isEmpty(time)){ //判断时间是否为空 + request.getSession().setAttribute("time", formater.format(date)); //为空重新添加缓存时间 + time = request.getSession().getAttribute("time"); + } + Date joinTime = formater.parse(String.valueOf(time)); + String dateStart = formater.format(joinTime); + Date d1=formater.parse(dateStart); + // 时间差: + long diff = date.getTime() - d1.getTime(); + long diffSeconds = diff / 1000 % 60; + String ip=request.getRemoteAddr(); + ServletOutputStream sos = null; + if (ObjectUtils.isEmpty(sessionCode) || diffSeconds > 50){ //判断验证码是否为空 为空重新生成 判断是否在有效时间内 默认50秒 + Map codeMap = RandomValidateCodeUtil.generateCodeAndPic(ip,sessionCode,0); + // 验证码存入session + request.getSession().setAttribute("code", codeMap.get("code").toString()); + // 时间存入session + request.getSession().setAttribute("time", formater.format(date)); + // 禁止图像缓存。 + response.setHeader("Pragma", "no-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setDateHeader("Expires", -1); + response.setContentType("image/jpeg"); + // 将图像输出到Servlet输出流中。 + try { + sos = response.getOutputStream(); + ImageIO.write((RenderedImage) codeMap.get("codePic"), "jpeg", sos); + } catch (IOException e) { + e.printStackTrace(); + } finally { + assert sos != null; + sos.close(); + } + }else { + // System.out.println("请输入你的姓名:"); + Map codeMap = RandomValidateCodeUtil.generateCodeAndPic(ip,sessionCode,1); + // 禁止图像缓存。 + response.setHeader("Pragma", "no-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setDateHeader("Expires", -1); + response.setContentType("image/jpeg"); + // 将图像输出到Servlet输出流中。 + try { + sos = response.getOutputStream(); + ImageIO.write((RenderedImage) codeMap.get("codePic"), "jpeg", sos); + } catch (IOException e) { + e.printStackTrace(); + } finally { + assert sos != null; + sos.close(); + } + + } + + } /** * 通过api接口入队 diff --git a/server/src/main/java/cn/keking/web/filter/AttributeSetFilter.java b/server/src/main/java/cn/keking/web/filter/AttributeSetFilter.java index 54fab983..933e8cf5 100644 --- a/server/src/main/java/cn/keking/web/filter/AttributeSetFilter.java +++ b/server/src/main/java/cn/keking/web/filter/AttributeSetFilter.java @@ -42,6 +42,7 @@ public class AttributeSetFilter implements Filter { request.setAttribute("fileUploadDisable", ConfigConstants.getFileUploadDisable()); request.setAttribute("beian", ConfigConstants.getBeian()); request.setAttribute("size", ConfigConstants.maxSize()); + request.setAttribute("deleteCaptcha", ConfigConstants.getDeleteCaptcha()); } /** diff --git a/server/src/main/resources/web/main/index.ftl b/server/src/main/resources/web/main/index.ftl index b4f5408f..4a27bd3f 100644 --- a/server/src/main/resources/web/main/index.ftl +++ b/server/src/main/resources/web/main/index.ftl @@ -111,6 +111,52 @@ + <#if deleteCaptcha > + <#-- 获取删除吗 --> +
+
+

获取删除码(注意:每个验证码只能删除一个文件,验证码有效期为50秒)

+
+
+ + +
+
+ + <#-- 预览测试 -->
@@ -164,7 +210,11 @@