用Java验证pdf文件的电子章签名
rm-rf* 人气:0这篇文章主要介绍了如何用Java验证pdf文件的电子章签名,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yalong</groupId> <artifactId>verifyPdf</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <lombok.version>1.18.10</lombok.version> </properties> <dependencies> <!-- <dependency>--> <!-- <groupId> e-iceblue </groupId>--> <!-- <artifactId>spire.pdf</artifactId>--> <!-- <version>3.4.2</version>--> <!-- </dependency>--> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>e-iceblue</groupId> <artifactId>spire.pdf.free</artifactId> <version>2.6.3</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0.1</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> </dependencies> <repositories> <repository> <id>com.e-iceblue</id> <url>http://repo.e-iceblue.cn/repository/maven-public/</url> </repository> </repositories> </project>
VerifySignature.java
import com.spire.pdf.PdfDocument; import com.spire.pdf.security.PdfCertificate; import com.spire.pdf.security.PdfSignature; import com.spire.pdf.widget.PdfFormFieldWidgetCollection; import com.spire.pdf.widget.PdfFormWidget; import com.spire.pdf.widget.PdfSignatureFieldWidget; import lombok.Data; import lombok.ToString; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.*; import java.awt.*; @Data @ToString class ExcelDataVO implements Serializable { private String fileName; private String signDate; private String validBefore; private String validAfter; private String subject; private String serialNumber; private Boolean isEffective = false; } class ExcelWriter { //表头 private static final List<String> CELL_HEADS; static { // 类装载时就载入指定好的表头信息,如有需要,可以考虑做成动态生成的表头 CELL_HEADS = new ArrayList<>(); CELL_HEADS.add("文件名"); CELL_HEADS.add("签名时间"); CELL_HEADS.add("有效期"); CELL_HEADS.add("有效期"); CELL_HEADS.add("签名机构"); CELL_HEADS.add("序列号"); CELL_HEADS.add("是否通过验签"); } /** * 生成Excel并写入数据信息 * * @param dataList 数据列表 * @return 写入数据后的工作簿对象 */ public static Workbook exportData(List<ExcelDataVO> dataList) { // 生成xlsx的Excel Workbook workbook = new SXSSFWorkbook(); // 如需生成xls的Excel,请使用下面的工作簿对象,注意后续输出时文件后缀名也需更改为xls //Workbook workbook = new HSSFWorkbook(); // 生成Sheet表,写入第一行的表头 Sheet sheet = buildDataSheet(workbook); //构建每行的数据内容 int rowNum = 1; for (ExcelDataVO data : dataList) { if (data == null) { continue; } //输出行数据 Row row = sheet.createRow(rowNum++); convertDataToRow(workbook, data, row); } return workbook; } /** * 生成sheet表,并写入第一行数据(表头) * * @param workbook 工作簿对象 * @return 已经写入表头的Sheet */ private static Sheet buildDataSheet(Workbook workbook) { Sheet sheet = workbook.createSheet(); // 设置表头宽度 for (int i = 0; i < CELL_HEADS.size(); i++) { sheet.setColumnWidth(i, 4000); } // 设置默认行高 sheet.setDefaultRowHeight((short) 400); // 构建头单元格样式 CellStyle cellStyle = buildHeadCellStyle(sheet.getWorkbook()); // 写入第一行各列的数据 Row head = sheet.createRow(0); for (int i = 0; i < CELL_HEADS.size(); i++) { Cell cell = head.createCell(i); cell.setCellValue(CELL_HEADS.get(i)); cell.setCellStyle(cellStyle); } return sheet; } /** * 设置第一行表头的样式 * * @param workbook 工作簿对象 * @return 单元格样式对象 */ private static CellStyle buildHeadCellStyle(Workbook workbook) { CellStyle style = workbook.createCellStyle(); //对齐方式设置 style.setAlignment(HorizontalAlignment.CENTER); //边框颜色和宽度设置 style.setBorderBottom(BorderStyle.THIN); style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 下边框 style.setBorderLeft(BorderStyle.THIN); style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 左边框 style.setBorderRight(BorderStyle.THIN); style.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 右边框 style.setBorderTop(BorderStyle.THIN); style.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 上边框 //设置背景颜色 style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); style.setFillPattern(FillPatternType.SOLID_FOREGROUND); //粗体字设置 Font font = workbook.createFont(); font.setBold(true); style.setFont(font); return style; } /** * 将数据转换成行 * * @param data 源数据 * @param row 行对象 */ private static void convertDataToRow(Workbook workbook, ExcelDataVO data, Row row) { int cellNum = 0; Cell cell; //对特殊数值设置颜色 CellStyle cellStyle = workbook.createCellStyle(); //字体设置 Font font = workbook.createFont(); font.setBold(true); font.setColor(IndexedColors.GREEN.getIndex()); cellStyle.setFont(font); // 文件名 cell = row.createCell(cellNum++); cell.setCellValue(data.getFileName()); // 签名时间 cell = row.createCell(cellNum++); cell.setCellValue(null == data.getSignDate() ? "" : data.getSignDate()); // 有效期 cell = row.createCell(cellNum++); cell.setCellValue(null == data.getValidBefore() ? "" : data.getValidBefore()); // 有效期 cell = row.createCell(cellNum++); cell.setCellValue(null == data.getValidAfter() ? "" : data.getValidAfter()); //主题 cell = row.createCell(cellNum++); cell.setCellValue(null == data.getSubject() ? "" : data.getSubject()); //序列号 cell = row.createCell(cellNum++); cell.setCellValue(null == data.getSerialNumber() ? "" : data.getSerialNumber()); //是否通过验签 cell = row.createCell(cellNum); if (data.getIsEffective()) { cell.setCellValue("签名有效"); } else { cell.setCellValue("签名无效"); cell.setCellStyle(cellStyle); } } public static void writeExcel(List<ExcelDataVO> dataVOList, String exportFilePath) { // 写入数据到工作簿对象内 Workbook workbook = ExcelWriter.exportData(dataVOList); // 以文件的形式输出工作簿对象 FileOutputStream fileOut = null; try { File exportFile = new File(exportFilePath); if (!exportFile.exists()) { boolean newFile = exportFile.createNewFile(); if (!newFile) { System.out.println("文件创建失败"); } } fileOut = new FileOutputStream(exportFilePath); workbook.write(fileOut); fileOut.flush(); } catch (Exception e) { System.out.println("输出Excel时发生错误,错误原因:" + e.getMessage()); } finally { try { if (null != fileOut) { fileOut.close(); } workbook.close(); } catch (IOException e) { System.out.println("关闭输出流时发生错误,错误原因:" + e.getMessage()); } } } } public class VerifySignature { private static String fromDirPath; private static String toFilePath; public static void main(String[] args) { final JFrame jf = new JFrame("测试窗口"); jf.setSize(400, 250); jf.setLocationRelativeTo(null); jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); JPanel panel = new JPanel(); // 创建文本区域, 用于显示相关信息 final JTextArea msgTextArea = new JTextArea(10, 30); msgTextArea.setLineWrap(true); panel.add(msgTextArea); JButton openBtn = new JButton("选择文件路径"); openBtn.addActionListener(e -> showFileOpenDialog(jf, msgTextArea)); panel.add(openBtn); JButton saveBtn = new JButton("结果保存位置"); saveBtn.addActionListener(e -> showFileSaveDialog(jf, msgTextArea)); panel.add(saveBtn); jf.setContentPane(panel); jf.setVisible(true); JButton enSureBtn = new JButton("确认"); enSureBtn.addActionListener(e -> enSureListener(jf)); panel.add(enSureBtn); jf.setContentPane(panel); jf.setVisible(true); } /* * 打开文件 */ private static void showFileOpenDialog(Component parent, JTextArea msgTextArea) { // 创建一个默认的文件选取器 JFileChooser fileChooser = new JFileChooser(); // 设置默认显示的文件夹为当前文件夹 fileChooser.setCurrentDirectory(new File(".")); // 设置文件选择的模式(只选文件、只选文件夹、文件和文件均可选) fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); // 设置是否允许多选 fileChooser.setMultiSelectionEnabled(false); // // 添加可用的文件过滤器(FileNameExtensionFilter 的第一个参数是描述, 后面是需要过滤的文件扩展名 可变参数) // fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("zip(*.zip, *.rar)", "zip", "rar")); // // // 设置默认使用的文件过滤器 // fileChooser.setFileFilter(new FileNameExtensionFilter("image(*.jpg, *.png, *.gif)", "jpg", "png", "gif")); // 打开文件选择框(线程将被阻塞, 直到选择框被关闭) int result = fileChooser.showOpenDialog(parent); if (result == JFileChooser.APPROVE_OPTION) { // 如果点击了"确定", 则获取选择的文件路径 File file = fileChooser.getSelectedFile(); fromDirPath = file.getAbsolutePath(); msgTextArea.append("选择源文件: " + fromDirPath + "\n\n"); } } /* * 选择文件保存路径 */ private static void showFileSaveDialog(Component parent, JTextArea msgTextArea) { // 创建一个默认的文件选取器 JFileChooser fileChooser = new JFileChooser(); //把时间戳经过处理得到期望格式的时间 Date date = new Date(); SimpleDateFormat format0 = new SimpleDateFormat("yyyyMMddHHmmss"); String now = format0.format(date.getTime()); // 设置打开文件选择框后默认输入的文件名 fileChooser.setSelectedFile(new File(now + ".xlsx")); // 打开文件选择框(线程将被阻塞, 直到选择框被关闭) int result = fileChooser.showSaveDialog(parent); if (result == JFileChooser.APPROVE_OPTION) { // 如果点击了"保存", 则获取选择的保存路径 File file = fileChooser.getSelectedFile(); toFilePath = file.getAbsolutePath(); msgTextArea.append("结果文件路径: " + toFilePath + "\n\n"); } } //找到需要的内容 public final static Pattern pattern = Pattern.compile("\\[Subject\\].*?O=(.*?),.*?\\[Issuer\\](.*?)\\[Serial Number\\](.*?)\\[Not Before\\](.*?)\\[Not After\\](.*?)\\[Thumbprint\\](.*?)"); // 剔除特殊字符 public final static Pattern replacePattern = Pattern.compile("\t|\r|\n"); /** * 查找某个路径下的所有pdf文件 * * @return 所有的pdf绝对路径 */ public static HashSet<String> listDir(String path) { HashSet<String> FileNameString = new HashSet<String>(); File file = new File(path); //获取其file对象 File[] fs = file.listFiles(); //遍历path下的文件和目录,放在File数组中 if (fs == null) { System.out.println(path + "路径下没有文件"); return null; } //遍历File[]数组 for (File f : fs) { String fileName = String.valueOf(f); if (!f.isDirectory() && fileName.toLowerCase().endsWith(".pdf")) //若非目录(即文件),则打印 FileNameString.add(fileName); } return FileNameString; } /** * 检验pdf文件是否签名 * * @param filePath pdf文件绝对路径 */ public static ExcelDataVO checkPdf(String filePath) { //创建PdfDocument实例 PdfDocument doc = new PdfDocument(); //创建结果集 ExcelDataVO excelDataVO = new ExcelDataVO(); //文件名,注意windows下应该是\\,linux下是/ String fileName = filePath.substring(filePath.lastIndexOf("\\") + 1); excelDataVO.setFileName(fileName); //加载含有签名的PDF文件 doc.loadFromFile(filePath); //获取域集合 PdfFormWidget pdfFormWidget = (PdfFormWidget) doc.getForm(); PdfFormFieldWidgetCollection pdfFormFieldWidgetCollection = pdfFormWidget.getFieldsWidget(); // int countCollection = pdfFormFieldWidgetCollection.getCount(); // System.out.println("共发现" + countCollection + "个域"); //遍历域 for (int i = 0; i < pdfFormFieldWidgetCollection.getCount(); i++) { //判定是否为签名域 if (pdfFormFieldWidgetCollection.get(i) instanceof PdfSignatureFieldWidget) { //获取签名域 PdfSignatureFieldWidget signatureFieldWidget = (PdfSignatureFieldWidget) pdfFormFieldWidgetCollection.get(i); //获取签名时间 PdfSignature signature = signatureFieldWidget.getSignature(); excelDataVO.setSignDate(String.valueOf(signature.getDate())); //获取签名的内容 PdfCertificate certificate = signature.getCertificate(); // System.out.println("Issuer:" + certificate.getIssuer()); // System.out.println("Subject:" + certificate.getSubject()); // System.out.println("---------"); // excelDataVO.setSubject(String.valueOf(certificate.getSubject())); String certificateString = certificate.toString(); Matcher m = replacePattern.matcher(certificateString); certificateString = m.replaceAll(""); Matcher matcher = pattern.matcher(certificateString); while (matcher.find()) { // String group = matcher.group(0); String subject = matcher.group(1); // String issuer = matcher.group(2); String serialNumber = matcher.group(3); String before = matcher.group(4); String after = matcher.group(5); // String sha1 = matcher.group(6); excelDataVO.setSubject(subject); excelDataVO.setSerialNumber(serialNumber); excelDataVO.setValidBefore(before); excelDataVO.setValidAfter(after); } //判定签名是否有效 boolean result = signature.verifySignature(); excelDataVO.setIsEffective(result); if (result) { return excelDataVO; } } } return excelDataVO; } /* * 开始执行业务逻辑 */ private static void enSureListener(JFrame parent) { parent.dispose(); System.out.println("开始验签..."); //从某个路径下获取所有的pdf文件路径 HashSet<String> filePaths = listDir(fromDirPath); if (filePaths == null) { return; } List<ExcelDataVO> excelDataVOS = new ArrayList<>(); for (String filePath : filePaths) { ExcelDataVO excelDataVO = checkPdf(filePath); excelDataVOS.add(excelDataVO); } ExcelWriter.writeExcel(excelDataVOS, toFilePath); System.out.println("验签完成..."); } }
加载全部内容