如何在JAXB中实现数字签名(Java + XAdES场景适用)
JAXB生成XML后添加XAdES数字签名实现方案
前置依赖
基于Java原生XML数字签名API + xades4j库实现,Maven依赖配置如下:
<dependency> <groupId>com.googlecode.xades4j</groupId> <artifactId>xades4j</artifactId> <version>1.6.0</version> </dependency>
整体实现逻辑
不用修改原有JAXB编组逻辑,直接在JAXB生成XML的内存对象上附加签名即可,流程如下:
- JAXB对象直接编组为DOM文档,避免文件IO开销
- 加载密钥与证书信息
- 配置XAdES签名参数
- 执行签名并插入到XML指定位置
- 输出签名后的XML文件
完整示例代码
1. JAXB对象转DOM文档
// 替换为你自己的JAXB根节点类 JAXBContext jaxbContext = JAXBContext.newInstance(YourRootClass.class); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // 构造命名空间感知的DOM文档 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().newDocument(); // 替换为你自己的JAXB实例对象 marshaller.marshal(yourJaxbRootObject, doc);
2. XAdES签名核心实现
import org.w3c.dom.Document; import xades4j.production.XadesBesSigningProfile; import xades4j.production.XadesSigner; import xades4j.properties.DataObjectDesc; import xades4j.properties.DataObjectReference; import xades4j.properties.SignedDataObjects; import xades4j.algorithms.EnvelopedSignatureTransform; import java.io.FileInputStream; import java.io.FileOutputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.X509Certificate; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; // 加载密钥库,示例用JKS格式,可替换为PKCS12等其他格式 KeyStore ks = KeyStore.getInstance("JKS"); try(FileInputStream fis = new FileInputStream("your_keystore_path.jks")) { ks.load(fis, "your_keystore_password".toCharArray()); } KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry( "your_key_alias", new KeyStore.PasswordProtection("your_key_password".toCharArray()) ); X509Certificate signingCert = (X509Certificate) keyEntry.getCertificate(); PrivateKey signingKey = keyEntry.getPrivateKey(); // 初始化XAdES-BES签名配置,可根据需求替换为XAdES-T等其他格式 XadesBesSigningProfile signingProfile = new XadesBesSigningProfile(keyEntry); XadesSigner signer = signingProfile.newSigner(); // 配置签名范围:空URI代表签名整个文档,如需签名特定节点改为`#nodeId`即可 DataObjectDesc signedObject = new DataObjectReference("") .withTransform(new EnvelopedSignatureTransform()); SignedDataObjects signedDataObjects = new SignedDataObjects(signedObject); // 执行签名,默认插入到根节点下,可传入指定DOM节点修改插入位置 signer.sign(signedDataObjects, doc.getDocumentElement()); // 输出签名后的XML文件 Transformer transformer = TransformerFactory.newInstance().newTransformer(); try(FileOutputStream fos = new FileOutputStream("signed_output.xml")) { transformer.transform(new DOMSource(doc), new StreamResult(fos)); }
常见调整说明
- 密钥来源可根据业务场景替换为UKey、云KMS等其他存储方式,只需正确获取
PrivateKey和对应签名证书即可 - 如需添加时间戳扩展为XAdES-T格式,只需在签名Profile中配置时间戳服务地址即可
- 如遇到加密算法不支持报错,可升级JDK版本或替换JCE无限制权限政策文件
内容的提问来源于stack exchange,提问作者Kiara
相关产品推荐
相关产品推荐

