- 您使用了错误的iText版本,因此您创建的签名不能为将来使用(请阅读本书以了解代码有什么问题)。
- 您取决于操作系统是Windows的事实。您的服务器也是Windows服务器吗?如果它是Linux服务器,则您的代码将不起作用。请与您的托管服务提供商联系,并询问您的托管服务提供商是否允许您在该服务器上拥有USB令牌(如果它不是专用服务器,则他们很可能会拒绝这样做)。
- 您正在使用Windows-MY,这意味着您将身份验证委派给操作系统。如果USB需要密码(通常是这样),则Windows将打开一个对话框供您填写该密码。如果将其部署在服务器上:每次有人请求签名时,都会有人坐在该服务器旁边来填写该密码吗?
- USB令牌旨在供人们手动签名文档。它们通常具有特定的限制。例如:通常,您每秒不能应用超过1个签名。在网络环境中,这通常是不够的。在Web环境中,您应该使用在服务器上安装硬件安全模块(HSM)。
虽然您的代码理论上可以在服务器上工作,但是我看到很多原因,为什么在客户端/服务器环境中使用在独立计算机上运行的代码不是明智的决定。有太多实际问题(例如身份验证,速度,iText版本错误等)会使您的项目出错。对于您的问题,该代码是否可以在客户端/服务器方案中运行,我将回答“否”。
更新:
在对我的答案的评论中,表明您的服务器是Linux服务器。很明显,在Linux服务器上使用“ Windows-
MY”将永远无效。您必须使用PKCS#11而不是Windows-MY与存储令牌的硬件设备通信。这是一个代码示例,可用于SafeNet的Luna
SA。如您所见,它使用PKCS#11:
import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.security.GeneralSecurityException;import java.security.KeyStore;import java.security.PrivateKey;import java.security.Provider;import java.security.Security;import java.security.cert.Certificate;import java.security.cert.X509Certificate;import java.util.ArrayList;import java.util.Collection;import java.util.List;import java.util.Properties;import org.bouncycastle.jce.provider.BouncyCastleProvider;import sun.security.pkcs11.SunPKCS11;import com.itextpdf.text.documentException;import com.itextpdf.text.Rectangle;import com.itextpdf.text.log.LoggerFactory;import com.itextpdf.text.log.SysoLogger;import com.itextpdf.text.pdf.PdfReader;import com.itextpdf.text.pdf.PdfSignatureAppearance;import com.itextpdf.text.pdf.PdfStamper;import com.itextpdf.text.pdf.security.BouncyCastleDigest;import com.itextpdf.text.pdf.security.CertificateUtil;import com.itextpdf.text.pdf.security.CrlClient;import com.itextpdf.text.pdf.security.CrlClientOnline;import com.itextpdf.text.pdf.security.DigestAlgorithms;import com.itextpdf.text.pdf.security.ExternalDigest;import com.itextpdf.text.pdf.security.ExternalSignature;import com.itextpdf.text.pdf.security.MakeSignature;import com.itextpdf.text.pdf.security.OcspClient;import com.itextpdf.text.pdf.security.OcspClientBouncyCastle;import com.itextpdf.text.pdf.security.PrivateKeySignature;import com.itextpdf.text.pdf.security.TSAClient;import com.itextpdf.text.pdf.security.TSAClientBouncyCastle;import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;public class C4_01_SignWithPKCS11HSM { public static final String SRC = "/home/itext/hello.pdf"; public static final String PROPS = "/home/itext/key.properties"; public static final String DEST = "/home/itext/hello_hsm.pdf"; public void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm, String provider, CryptoStandard subfilter, String reason, String location, Collection<CrlClient> crlList, OcspClient ocspClient, TSAClient tsaClient, int estimatedSize) throws GeneralSecurityException, IOException, documentException { // Creating the reader and the stamper PdfReader reader = new PdfReader(src); FileOutputStream os = new FileOutputStream(dest); PdfStamper stamper = PdfStamper.createSignature(reader, os, ' '); // Creating the appearance PdfSignatureAppearance appearance = stamper.getSignatureAppearance(); appearance.setReason(reason); appearance.setLocation(location); appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig"); // Creating the signature ExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider); ExternalDigest digest = new BouncyCastleDigest(); MakeSignature.signDetached(appearance, digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter); } public static void main(String[] args) throws IOException, GeneralSecurityException, documentException { LoggerFactory.getInstance().setLogger(new SysoLogger()); Properties properties = new Properties(); properties.load(new FileInputStream(PROPS)); char[] pass = properties.getProperty("PASSWORD").toCharArray(); String pkcs11cfg = properties.getProperty("PKCS11CFG"); BouncyCastleProvider providerBC = new BouncyCastleProvider(); Security.addProvider(providerBC); FileInputStream fis = new FileInputStream(pkcs11cfg); Provider providerPKCS11 = new SunPKCS11(fis); Security.addProvider(providerPKCS11); KeyStore ks = KeyStore.getInstance("PKCS11"); ks.load(null, pass); String alias = (String)ks.aliases().nextElement(); PrivateKey pk = (PrivateKey)ks.getKey(alias, pass); Certificate[] chain = ks.getCertificateChain(alias); OcspClient ocspClient = new OcspClientBouncyCastle(); TSAClient tsaClient = null; for (int i = 0; i < chain.length; i++) { X509Certificate cert = (X509Certificate)chain[i]; String tsaUrl = CertificateUtil.getTSAURL(cert); if (tsaUrl != null) { tsaClient = new TSAClientBouncyCastle(tsaUrl); break; } } List<CrlClient> crlList = new ArrayList<CrlClient>(); crlList.add(new CrlClientonline(chain)); C4_01_SignWithPKCS11HSM app = new C4_01_SignWithPKCS11HSM(); app.sign(SRC, DEST, chain, pk, DigestAlgorithms.SHA256, providerPKCS11.getName(), CryptoStandard.CMS, "HSM test", "Ghent", crlList, ocspClient, tsaClient, 0); }}使用的配置文件的内容如下所示:
Name = Lunalibrary = /usr/lunasa/lib/libCryptoki2_64.soslot = 1
请注意,根据
so您的情况,可能在另一个目录中,并且您的证书可能在另一个插槽中。我还使用属性文件来存储证书的密码。显然,我不会共享密码;-)
此示例已在GlobalSign拥有的服务器上使用GlobalSign证书进行了测试。



