alibaba / easyexcel

快速、简洁、解决大文件内存溢出的java处理Excel工具
https://easyexcel.opensource.alibaba.com
Apache License 2.0
31.64k stars 7.46k forks source link

Excel 加密处理文件类型问题 #3463

Open ex34toway opened 11 months ago

ex34toway commented 11 months ago

使用 EasyExcel 写加密后 xlsx 文档,并设置密码。读取的时候,不能设置 excelType 为 xlsx,否则报错;

代码复现

        final List<DataVo> dataList = new ArrayList<>();
        try (final FileOutputStream output = new FileOutputStream(new File("file.xlsx"))) {
            try (final ExcelWriter excelWriter =
                         EasyExcel.write(output, DataVo.class)
                                 .excelType(ExcelTypeEnum.XLSX)
                                 .charset(StandardCharsets.UTF_8)
                                 .password("password")
                                 .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                                 .build()) {
                WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
                excelWriter.write(dataList, writeSheet);
                excelWriter.finish();
            }
        }
        EasyExcel.read(
                        new FileInputStream("file.xlsx"),
                        DataVo.class,
                        new FileLisnter()
                )
                .password("password")
                .excelType(ExcelTypeEnum.XLSX)
                .sheet(0)
                .doRead();

目前了解到的细节

  1. 不设置 excelType 时,easyexcel 默认 ExcelTypeEnum.valueOf 会返回 xls.;
  2. 使用 Microsoft Office 使用密码能正常打 file.xlsx ,并没有提示文件格式问题;
youlingdada commented 10 months ago

第一个方法,可以试试在设置excelType后设置密码

youlingdada commented 10 months ago

第二个方法,就是提前对excel文件解密,然后解密的数据使用EasyExcel读,相关用例如下


import org.junit.jupiter.api.Test;

public class MyTest {
    @Test
    public void test() {
        final List<DemoData> dataList = new ArrayList<>();

        DemoData demoData = new DemoData();
        demoData.setId(System.currentTimeMillis());
        demoData.setString("你好");
        demoData.setDate(new Date());
        demoData.setDoubleData(23.0);
        dataList.add(demoData);

        try (final FileOutputStream output = new FileOutputStream("file.xlsx")) {
            try (final ExcelWriter excelWriter =
                         EasyExcel.write(output, DemoData.class)
                                 .excelType(ExcelTypeEnum.XLSX)
                                 .charset(StandardCharsets.UTF_8)
                                 .password("password")
                                 .build()) {
                WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
                excelWriter.write(dataList, writeSheet);
                excelWriter.finish();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        FileInputStream fis = new FileInputStream("file.xlsx");
        POIFSFileSystem fs = new POIFSFileSystem(fis);
        EncryptionInfo info = new EncryptionInfo(fs);
        Decryptor decryptor = Decryptor.getInstance(info);
        decryptor.verifyPassword("password");
        InputStream dataStream = decryptor.getDataStream(fs);

        EasyExcel.read(dataStream)
//                .password("password")
                .excelType(ExcelTypeEnum.XLSX)
                .head(DemoData.class)
                .registerReadListener(
                        new ReadListener<DemoData>() {
                            @Override
                            public void invoke(DemoData data, AnalysisContext context) {
                                System.out.println(data);
                            }

                            @Override
                            public void doAfterAllAnalysed(AnalysisContext context) {

                            }
                        }
                )
                .sheet()
                .doRead();
    }
}```
ex34toway commented 10 months ago

第一个方法,可以试试在设置excelType后设置密码

这个方法没用

ex34toway commented 10 months ago

第二个方法,就是提前对excel文件解密,然后解密的数据使用EasyExcel读,相关用例如下

import org.junit.jupiter.api.Test;

public class MyTest {
    @Test
    public void test() {
        final List<DemoData> dataList = new ArrayList<>();

        DemoData demoData = new DemoData();
        demoData.setId(System.currentTimeMillis());
        demoData.setString("你好");
        demoData.setDate(new Date());
        demoData.setDoubleData(23.0);
        dataList.add(demoData);

        try (final FileOutputStream output = new FileOutputStream("file.xlsx")) {
            try (final ExcelWriter excelWriter =
                         EasyExcel.write(output, DemoData.class)
                                 .excelType(ExcelTypeEnum.XLSX)
                                 .charset(StandardCharsets.UTF_8)
                                 .password("password")
                                 .build()) {
                WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
                excelWriter.write(dataList, writeSheet);
                excelWriter.finish();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        FileInputStream fis = new FileInputStream("file.xlsx");
        POIFSFileSystem fs = new POIFSFileSystem(fis);
        EncryptionInfo info = new EncryptionInfo(fs);
        Decryptor decryptor = Decryptor.getInstance(info);
        decryptor.verifyPassword("password");
        InputStream dataStream = decryptor.getDataStream(fs);

        EasyExcel.read(dataStream)
//                .password("password")
                .excelType(ExcelTypeEnum.XLSX)
                .head(DemoData.class)
                .registerReadListener(
                        new ReadListener<DemoData>() {
                            @Override
                            public void invoke(DemoData data, AnalysisContext context) {
                                System.out.println(data);
                            }

                            @Override
                            public void doAfterAllAnalysed(AnalysisContext context) {

                            }
                        }
                )
                .sheet()
                .doRead();
    }
}```

这个建议封装到 easyexcel 内部,自动识别是否是加密文档。如果是,直接提示需要密码即可。

youlingdada commented 10 months ago

这个bug现在我在尝试修复,目前能给出的解决办法就是这样,这个内部是实现了这个解密逻辑的,但是不知道什么原因没有生效,导致没有解密成功,进而影响了解析