minio文件上传-获取真实文件类型

文件上传

注意:以下内容包含

  1. 完成minio文件上传功能
  2. 完成minio文件下载功能
  3. 解决文件名称后缀与真实文件后缀不符问题
  4. 过滤xxs攻击的文件
  5. 校验pdf中js属性xxs攻击

1.添加pom依赖

<!--springboot版本 2.3.12.RELEASE-->

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- iText依赖 -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13.3</version>
        </dependency>
        <!-- 获取真实文件后缀 -->
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-core</artifactId>
            <version>1.28.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-parsers</artifactId>
            <version>1.28.2</version>
        </dependency>

        <dependency>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
            <version>2.12.0</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!-- minio -->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.7</version>
            <exclusions>
                <exclusion>
                    <artifactId>jackson-core</artifactId>
                    <groupId>com.fasterxml.jackson.core</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>okhttp</artifactId>
                    <groupId>com.squareup.okhttp3</groupId>
                </exclusion>
            </exclusions>
        </dependency>
    
        <!-- 解决minio启动报错 -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.12.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
</dependencies>

2.application.yml配置

#port
server:
  port: 9911

#minio
minio:
  endpoint: http://172.21.40.72:9001/ # minio服务地址
  accessKey: lIGhSpx5U2N0nKMCPKz2 # 桶key
  secretKey: q44dP2sTmLdbDWAI5mdCn06st5IOWN6nnUPOgtbF #桶value
  bucket-fuyao-public: fuyao-public #公开桶

3.minio配置类

@Configuration
public class MinIoConfig {

    @Value("${minio.endpoint}")
    private String endpoint;
    @Value("${minio.accessKey}")
    private String accessKey;
    @Value("${minio.secretKey}")
    private String secretKey;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }
}

4.工具类

@Slf4j
public class PdfUtils {

    /*根据输入流判断该文件的真实文件类型*/
    public static boolean containsJavaScript(InputStream inputStream) {
        PdfReader reader = null;
        try {
            reader = new PdfReader(inputStream);
            for (int i = 1; i <= reader.getNumberOfPages(); i++) {
                PdfDictionary pageDict = reader.getPageN(i);
                PdfObject pdfObject = pageDict.get(PdfName.ANNOTS);
                if (pdfObject != null && pdfObject.isArray()) {
                    PdfArray pdfArray = (PdfArray) pdfObject;
                    for (int j = 0; j < pdfArray.size(); j++) {
                        PdfDictionary annotDict = pdfArray.getAsDict(j);
                        if (annotDict != null) {
                            PdfObject action = annotDict.get(PdfName.A);
                            if (action != null && action.isDictionary()) {
                                PdfDictionary actionDict = (PdfDictionary) action;
                                if (PdfName.JAVASCRIPT.equals(actionDict.get(PdfName.S))) {
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
            PdfDictionary catalog = reader.getCatalog();
            PdfDictionary names = catalog.getAsDict(PdfName.NAMES);
            if (names != null) {
                PdfDictionary javascript = names.getAsDict(PdfName.JAVASCRIPT);
                if (javascript != null) {
                    return true;
                }
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
        return false;
    }
}

5.实现类

@Slf4j
@Service
public class FileServiceImpl implements FileService {

    @Resource
    private MinioClient minioClient;

    @Value("${minio.bucket-fuyao-public}")
    private String bucketName;
    @Value("${minio.endpoint}")
    private String url;

    private static final Set<String> IMAGE_FORMATS = new HashSet<>();
    private static final Set<String> ZIP_FORMATS = new HashSet<>();
    private static final Set<String> FILE_FORMATS = new HashSet<>();
    private static final Set<String> VIDEO_FORMATS = new HashSet<>();
    private static final String SUFFIX_PDF = "application/pdf";

    static {
        // 初始化图片格式集合
        IMAGE_FORMATS.add("image/jpeg");
        IMAGE_FORMATS.add("image/png");
        IMAGE_FORMATS.add("image/gif");
        IMAGE_FORMATS.add("image/bmp");

        // 初始化压缩包格式集合
        ZIP_FORMATS.add("application/zip");
        ZIP_FORMATS.add("application/vnd.rar");
        ZIP_FORMATS.add("application/x-7z-compressed");
        ZIP_FORMATS.add("application/x-tar");
        ZIP_FORMATS.add("application/gzip");

        // 初始化其他文件格式集合
        FILE_FORMATS.add("text/plain");
        FILE_FORMATS.add("application/pdf");
        FILE_FORMATS.add("application/msword");
        FILE_FORMATS.add("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        FILE_FORMATS.add("application/vnd.ms-excel");
        FILE_FORMATS.add("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

        //视频
        VIDEO_FORMATS.add("video/mp4");
    }

    @Override
    public R upload(MultipartFile file) {
        try {
            // 检查文件是否为空
            long fileSize = file.getSize();
            if (fileSize == 0) {
                return R.error(Constant.FILE_IS_EMPTY);
            }
            // 获取文件的原始后缀
            Tika tika = new Tika();
            Metadata metadata = new Metadata();
            String realFileType = tika.detect(file.getInputStream(), metadata);
            String contentType = file.getContentType();
            System.out.println(contentType);
            if (!realFileType.contains(SUFFIX_VIDEO)) {
                if (!realFileType.equals(fileType)) {
                    return Pick.error(Constant.FILE_TYPE_ERROR);
                }
                if (realFileType.equals(SUFFIX_PDF)) {
                    try (InputStream inputStream = file.getInputStream()) {
                        if (PdfUtils.containsJavaScript(inputStream)) {
                            return Pick.error(Constant.FILE_PDF_CONTAIN_JS);
                        }
                    }
                }
            }
            // 是否支持文件格式
            String folder = verifyFileFormat(contentType);
            if (Objects.isNull(folder)) {
                return R.error(Constant.FILE_FORMAT_ERROR);
            }
            // 是否是pdf 且包含js属性
            if (SUFFIX_PDF.equals(contentType)) {
                try (InputStream inputStream = file.getInputStream()) {
                    if (PdfUtils.containsJavaScript(inputStream)) {
                        return R.error(Constant.FILE_PDF_CONTAIN_JS);
                    }
                }
            }
            String fileName = UUID.randomUUID().toString().replaceAll("-", "") + "-" + file.getOriginalFilename();
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(folder + fileName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
            return R.data(url + bucketName + "/" + folder + fileName);
        } catch (Exception e) {
            log.error(Constant.FILE_UPLOAD_ERROR, e.getMessage());
            return R.error(Constant.FILE_UPLOAD_ERROR);
        }

    }

    @Override
    public void download(String filename, HttpServletResponse response) {
        GetObjectArgs objectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(filename).build();
        try (GetObjectResponse res = minioClient.getObject(objectArgs)) {
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
                while ((len = res.read(buf)) != -1) {
                    os.write(buf, 0, len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                response.setCharacterEncoding("utf-8");
                // 设置强制下载不打开
                try (ServletOutputStream stream = response.getOutputStream()) {
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            log.error(Constant.FILE_DOWNLOAD_ERROR, e);
            throw new RuntimeException(Constant.FILE_DOWNLOAD_ERROR);
        }
    }

    /*根据文件类型上传对应minio文件夹位置*/
    private String verifyFileFormat(String contentType) {
        if (IMAGE_FORMATS.contains(contentType)) {
            return Constant.FILE_IMAGE;
        }
        if (ZIP_FORMATS.contains(contentType)) {
            return Constant.FILE_ZIP;
        }
        if (FILE_FORMATS.contains(contentType)) {
            return Constant.FILE_FILE;
        }
        if (VIDEO_FORMATS.contains(contentType)) {
            return Constant.FILE_VIDEO;
        }
        return null;
    }
}

6.测试

上传pdf中含有js属性的文件
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值