重构验证码删除文件的实现逻辑 (#479)

* 重构验证码删除文件的实现逻辑

* 移除未使用的依赖

* 微调描述信息
This commit is contained in:
kl
2023-08-11 16:39:07 +08:00
committed by GitHub
parent aa49cc6ac0
commit 0a8be8ac95
7 changed files with 230 additions and 213 deletions

View File

@@ -2,7 +2,9 @@ package cn.keking.web.controller;
import cn.keking.config.ConfigConstants;
import cn.keking.model.ReturnResponse;
import cn.keking.utils.DateUtils;
import cn.keking.utils.KkFileUtils;
import cn.keking.utils.CaptchaUtil;
import cn.keking.utils.RarUtils;
import cn.keking.utils.WebUtils;
import org.slf4j.Logger;
@@ -11,11 +13,16 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
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.File;
import java.io.IOException;
import java.io.InputStream;
@@ -24,9 +31,11 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import static cn.keking.utils.CaptchaUtil.*;
/**
* @author yudian-it
* 2017/12/1
* 2017/12/1
*/
@RestController
public class FileController {
@@ -35,6 +44,7 @@ public class FileController {
private final String fileDir = ConfigConstants.getFileDir();
private final String demoDir = "demo";
private final String demoPath = demoDir + File.separator;
public static final String BASE64_DECODE_ERROR_MSG = "Base64解码失败请检查你的 %s 是否采用 Base64 + urlEncode 双重编码了!";
@@ -61,28 +71,11 @@ public class FileController {
@GetMapping("/deleteFile")
public ReturnResponse<Object> deleteFile(HttpServletRequest request, String fileName, String password) {
ReturnResponse<Object> checkResult = this.deleteFileCheck(fileName);
ReturnResponse<Object> checkResult = this.deleteFileCheck(request, fileName, password);
if (checkResult.isFailure()) {
return checkResult;
}
fileName = checkResult.getContent().toString();
if(ConfigConstants.getDeleteCaptcha()){
String sessionCode;
try {
sessionCode = request.getSession().getAttribute("code").toString(); //获取已经保存的验证码
} catch (Exception e) {
sessionCode = "null";
}
if (!sessionCode.equalsIgnoreCase(password)){
logger.error("删除文件【{}】失败,密码错误!",fileName);
return ReturnResponse.failure("删除文件失败,密码错误!");
}
}else {
if(!ConfigConstants.getPassword().equalsIgnoreCase(password)) {
logger.error("删除文件【{}】失败,密码错误!",fileName);
return ReturnResponse.failure("删除文件失败,密码错误!");
}
}
fileName = checkResult.getContent().toString();
File file = new File(fileDir + demoPath + fileName);
logger.info("删除文件:{}", file.getAbsolutePath());
if (file.exists() && !file.delete()) {
@@ -90,10 +83,45 @@ public class FileController {
logger.error(msg);
return ReturnResponse.failure(msg);
}
request.getSession().removeAttribute("code"); //删除缓存验证码
WebUtils.removeSessionAttr(request, captcha_code); //删除缓存验证码
return ReturnResponse.success();
}
/**
* 验证码方法
*/
@RequestMapping("/deleteFile/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (!ConfigConstants.getDeleteCaptcha()) {
return;
}
response.setContentType("image/jpeg");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", -1);
String captchaCode = WebUtils.getSessionAttr(request, captcha_code);
long captchaGenerateTime = WebUtils.getLongSessionAttr(request, captcha_generate_time);
long timeDifference = DateUtils.calculateCurrentTimeDifference(captchaGenerateTime);
Map<String, Object> codeMap;
// 验证码为空且生成验证码超过50秒重新生成验证码
if (timeDifference > 50 && ObjectUtils.isEmpty(captchaCode)) {
codeMap = CaptchaUtil.generateCaptcha(null);
// 更新验证码
request.getSession().setAttribute(captcha_code, codeMap.get(captcha_code).toString());
request.getSession().setAttribute(captcha_generate_time, DateUtils.getCurrentSecond());
} else {
captchaCode = ObjectUtils.isEmpty(captchaCode) ? "wait" : captchaCode;
codeMap = CaptchaUtil.generateCaptcha(captchaCode);
}
ServletOutputStream sos = response.getOutputStream();
ImageIO.write((RenderedImage) codeMap.get(captcha_code_pic), "jpeg", sos);
sos.close();
}
@GetMapping("/listFiles")
public List<Map<String, String>> getFiles() {
List<Map<String, String>> list = new ArrayList<>();
@@ -121,7 +149,7 @@ public class FileController {
return ReturnResponse.failure("文件传接口已禁用");
}
String fileName = WebUtils.getFileNameFromMultipartFile(file);
if(fileName.lastIndexOf(".")==-1){
if (fileName.lastIndexOf(".") == -1) {
return ReturnResponse.failure("不允许上传的类型");
}
if (!KkFileUtils.isAllowedUpload(fileName)) {
@@ -144,7 +172,7 @@ public class FileController {
* @param fileName 文件名
* @return 校验结果
*/
private ReturnResponse<Object> deleteFileCheck(String fileName) {
private ReturnResponse<Object> deleteFileCheck(HttpServletRequest request, String fileName, String password) {
if (ObjectUtils.isEmpty(fileName)) {
return ReturnResponse.failure("文件名为空,删除失败!");
}
@@ -161,6 +189,16 @@ public class FileController {
if (KkFileUtils.isIllegalFileName(fileName)) {
return ReturnResponse.failure("非法文件名,删除失败!");
}
if (ObjectUtils.isEmpty(password)) {
return ReturnResponse.failure("密码 or 验证码为空,删除失败!");
}
String expectedPassword = ConfigConstants.getDeleteCaptcha() ? WebUtils.getSessionAttr(request, captcha_code) : ConfigConstants.getPassword();
if (!password.equalsIgnoreCase(expectedPassword)) {
logger.error("删除文件【{}】失败,密码错误!", fileName);
return ReturnResponse.failure("删除文件失败,密码错误!");
}
return ReturnResponse.success(fileName);
}

View File

@@ -1,6 +1,5 @@
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;
@@ -8,7 +7,6 @@ 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;
@@ -17,17 +15,12 @@ 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.io.UnsupportedEncodingException;
@@ -35,11 +28,8 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
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;
@@ -66,7 +56,7 @@ public class OnlinePreviewController {
@GetMapping( "/onlinePreview")
public String onlinePreview(String url, Model model, HttpServletRequest req) {
String fileUrl;
try {
fileUrl = WebUtils.decodeUrl(url);
@@ -199,82 +189,6 @@ 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<String, Object> 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<String, Object> 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接口入队