net.mingsoft.basic.aop.FileVerifyAop Maven / Gradle / Ivy
The newest version!
/**
* Copyright (c) 2012-present 铭软科技(mingsoft.net)
* 本软件及相关文档文件(以下简称“软件”)的版权归 铭软科技 所有
* 遵循 铭软科技《服务协议》中的《保密条款》
*/
package net.mingsoft.basic.aop;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import net.mingsoft.base.constant.Const;
import net.mingsoft.base.entity.ResultData;
import net.mingsoft.base.exception.BusinessException;
import net.mingsoft.base.util.BundleUtil;
import net.mingsoft.basic.bean.UploadConfigBean;
import net.mingsoft.basic.util.BasicUtil;
import net.mingsoft.config.MSProperties;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 验证zip是否合法的aop
* 重写basic增加自定义配置
*/
@Component
@Aspect
public class FileVerifyAop extends BaseAop{
private static final Logger LOGGER = LoggerFactory.getLogger(FileVerifyAop.class);
/**
* 切入点
*/
@Pointcut("execution(* net.mingsoft.basic.action.ManageFileAction.upload(..)) || " +
"execution(* net.mingsoft.basic.action.ManageFileAction.uploadTemplate(..))")
public void uploadPointCut(){}
/**
* 后台上传文件的时候,将验证zip里的文件
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("uploadPointCut()")
public Object uploadAop(ProceedingJoinPoint joinPoint) throws Throwable {
UploadConfigBean bean = super.getType(joinPoint, UploadConfigBean.class);
//检查文件类型
String uploadFileName = FileNameUtil.cleanInvalid(bean.getFile().getOriginalFilename());
if (StringUtils.isBlank(uploadFileName)) {
return ResultData.build().error("文件名不能为空!");
}
InputStream inputStream = null;
//校验压缩包里的文件
try {
inputStream = bean.getFile().getInputStream();
//文件的真实类型
String mimeType = BasicUtil.getMimeType(inputStream,uploadFileName);
if ("zip".equalsIgnoreCase(mimeType) || "zip".equalsIgnoreCase(FileNameUtil.extName(uploadFileName))) {
checkZip(bean.getFile(), false);
}
} catch (Exception e) {
return ResultData.build().error(e.getMessage());
}finally {
if (inputStream != null){
try {
inputStream.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return joinPoint.proceed();
}
/**
* web上传文件的时候,将验证zip里的文件
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("execution(* net.mingsoft.basic.action.web.FileAction.upload(..))")
public Object WebUploadAop(ProceedingJoinPoint joinPoint) throws Throwable {
UploadConfigBean bean = super.getType(joinPoint, UploadConfigBean.class);
//检查文件类型
String uploadFileName = FileNameUtil.cleanInvalid(bean.getFile().getOriginalFilename());
if (StringUtils.isBlank(uploadFileName)) {
return ResultData.build().error("文件名不能为空!");
}
InputStream inputStream = null;
//校验压缩包里的文件
try {
inputStream = bean.getFile().getInputStream();
//文件的真实类型
String mimeType = BasicUtil.getMimeType(inputStream,uploadFileName);
if ("zip".equalsIgnoreCase(mimeType) || "zip".equalsIgnoreCase(FileNameUtil.extName(uploadFileName))) {
checkZip(bean.getFile(), false);
}
} catch (Exception e) {
return ResultData.build().error(e.getMessage());
}finally {
if (inputStream != null){
try {
inputStream.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return joinPoint.proceed();
}
/**
* 检查压缩包
*/
private void checkZip(MultipartFile multipartFile, boolean isWeb) throws Exception{
//创建临时解压文件夹
File tempFilePath = FileUtil.mkdir(FileUtil.getTmpDirPath()+"/Zip"+IdUtil.simpleUUID());
File zipFile = FileUtil.file(tempFilePath.getAbsolutePath() + "/" + IdUtil.simpleUUID() +".zip");
InputStream inputStream = multipartFile.getInputStream();
FileUtils.copyInputStreamToFile(inputStream, zipFile);
FileInputStream fileInputStream = null;
try {
unzip(zipFile,tempFilePath.getAbsolutePath());
//获取文件夹下所有文件
List files = FileUtil.loopFiles(tempFilePath);
//移除压缩包自身
files.remove(zipFile);
//禁止上传的格式
List deniedList = Arrays.stream(MSProperties.upload.denied.split(",")).map(String::toLowerCase).collect(Collectors.toList());
for (File file : files) {
fileInputStream = new FileInputStream(file);
//文件的类型 受文件幻数影响
String fileType = FileTypeUtil.getType(file).toLowerCase();
// 文件后缀名
String fileSuffixName = FileUtil.getSuffix(file);
//通过yml的配置检查文件格式是否合法
if (deniedList.contains(fileSuffixName)){
IOUtils.closeQuietly(fileInputStream);
throw new RuntimeException(StrUtil.format("压缩包内文件{}后缀{}禁止上传",file.getName(),fileSuffixName));
}else if (deniedList.contains(fileType)){
IOUtils.closeQuietly(fileInputStream);
throw new RuntimeException(StrUtil.format("压缩包内文件{}的类型{}禁止上传",file.getName(),fileType));
}
IOUtils.closeQuietly(fileInputStream);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
IOUtils.closeQuietly(fileInputStream);
}
IOUtils.closeQuietly(inputStream);
FileUtil.del(tempFilePath);
}
}
/**
* 解压压缩包
* @param file
* @param descDir
* @throws IOException
*/
private void unzip(File file, String descDir) throws IOException {
ZipArchiveInputStream inputStream = new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(file)));
File pathFile = new File(descDir);
if (!pathFile.exists()) {
pathFile.mkdirs();
}
ZipArchiveEntry entry = null;
try {
while ((entry = inputStream.getNextZipEntry()) != null) {
if (entry.getName() == null && (entry.getName().contains("../") || entry.getName().contains("..\\"))) {
throw new BusinessException(BundleUtil.getString(Const.RESOURCES,"err.error",BundleUtil.getString(net.mingsoft.basic.constant.Const.RESOURCES,"file.name")));
}
String[] dirs = entry.getName().split("/");
String tempDir = descDir;
for(String dir:dirs) {
if(dir.indexOf(".")==-1) {
tempDir += File.separator.concat(dir);
FileUtil.mkdir(tempDir);
}
}
if (entry.isDirectory()) {
File directory = new File(descDir, entry.getName());
directory.mkdirs();
} else {
OutputStream os = null;
try {
LOGGER.debug("file name => {}",entry.getName());
try {
os = new BufferedOutputStream(new FileOutputStream(new File(descDir, entry.getName())));
//输出文件路径信息
IOUtils.copy(inputStream, os);
} catch (FileNotFoundException e) {
LOGGER.error("解压{}不存在",entry.getName());
e.printStackTrace();
}
} finally {
IOUtils.closeQuietly(os);
}
}
}
} catch (Exception e) {
// 只有篡改压缩包头信息才会抛出解压异常,空压缩包不抛异常,直接解压成功
LOGGER.error("解压文件{}失败",file.getName());
throw new BusinessException("压缩包文件异常");
} finally {
// 不管怎么样都关闭流
IOUtils.closeQuietly(inputStream);
}
}
}