All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy