跳至页脚内容
使用IRONPDF

如何在 ASP.NET Core 中添加 PDF 数字签名

在 ASP.NET Core 中为 PDF 添加数字签名可以保护文档完整性,确认签名者的身份,并使文件在大多数司法管辖区具有法律效力。 使用 IronPDF,您可以使用证书文件在服务器端对 PDF 进行签名,添加可见的签名图像,并嵌入交互式签名表单字段——所有这些都只需几行 C# 代码即可完成。

从 NuGet 安装库,获取您的 .pfx 证书,并按照以下示例构建可用于生产的文档签名工作流。

Install-Package IronPdf
dotnet add package IronPdf
Install-Package IronPdf
dotnet add package IronPdf
SHELL

您也可以通过 Visual Studio 中的 NuGet 包管理器安装它,或者直接从IronPDF 产品页面下载它。 立即开始免费试用,无需任何承诺即可体验所有签名功能。

什么是PDF数字签名?它为什么如此重要?

数字签名是一种加密机制,它将签名者的身份与特定版本的文档绑定在一起。 它与简单的电子签名(例如打字签名或扫描图像)不同,因为它使用公钥加密技术来创建可验证、防篡改的印章。

当有人对 PDF 文件进行数字签名时,签名软件会生成文档内容的哈希值,并使用签名者的私钥对该哈希值进行加密。 生成的签名会与签名者的公钥证书一起嵌入到 PDF 文件中。 任何支持数字签名的 PDF 阅读器(包括 Adobe Acrobat Reader 和现代浏览器内置的 PDF 查看器)都可以使用公钥解密哈希值,并将其与新计算的文档哈希值进行比较。 如果哈希值匹配,则该文档是真实且未被篡改的。

数字签名为何具有法律意义

在大多数国家,数字签名的文件与手写纸质合同具有同等的法律效力。 欧盟的eIDAS 法规和美国的ESIGN 法案都承认,在满足某些条件的情况下,电子签名具有法律约束力。 基于证书的数字签名满足了这些要求中的最高级别。

数字签名在 ASP.NET Core 中的作用

在 ASP.NET Core 应用程序中使用服务器端签名,可以在处理过程中自动对文档进行签名——无需客户端软件。 合同、发票、合规报告和保密协议都可以在生成后立即签署,签署后的文件可以直接返回给用户或存储在文档管理系统中。 IronPDF 处理从 HTML 到 PDF 渲染到加密签名的整个流程,因此您可以实现工作流程而无需触及底层 PDF 规范细节。

如何在 ASP.NET Core 项目中安装 IronPDF?

获得可用签名环境的最快途径是使用 NuGet 包。 在 Visual Studio 中打开软件包管理器控制台并运行:

Install-Package IronPdf
dotnet add package IronPdf
Install-Package IronPdf
dotnet add package IronPdf
SHELL

或者,在解决方案资源管理器中右键单击项目,选择"管理 NuGet 程序包",搜索 IronPdf,然后单击"安装"。 安装完成后,在控制器或服务类的顶部添加以下 using 指令:

using IronPdf;
using IronPdf.Signing;
using IronPdf;
using IronPdf.Signing;
Imports IronPdf
Imports IronPdf.Signing
$vbLabelText   $csharpLabel

IronPDF 的目标平台是 .NET 8 和 .NET 9/10,因此它能够自然地融入现代 ASP.NET Core 项目。 有关首次设置的详细步骤,请参阅IronPDF 快速入门指南

如何在 ASP.NET Core 中使用证书文件对 PDF 进行签名?

最常见的签名方法是使用 .pfx.p12 证书文件。这些文件将私钥和公钥证书链打包到一个受密码保护的存档中。您可以从受信任的证书颁发机构 (CA)(例如DigiCertGlobalSign )获取此类文件,或者生成自签名证书用于开发和测试。

以下示例从 HTML 生成 PDF,并应用基于证书的数字签名:

using IronPdf;
using IronPdf.Signing;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/sign-with-certificate", (IWebHostEnvironment env) =>
{
    // Generate a PDF from HTML content
    var renderer = new ChromePdfRenderer();
    var document = renderer.RenderHtmlAsPdf("<h1>Contract Agreement</h1><p>Terms and conditions...</p>");

    // Locate the PFX certificate on the server
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");

    // Build the signature object
    var signature = new PdfSignature(certPath, "yourPassword")
    {
        SigningContact = "legal@yourcompany.com",
        SigningLocation = "Chicago, IL, USA",
        SigningReason = "Document Approval"
    };

    // Apply the signature and save
    document.Sign(signature);
    string outputPath = Path.Combine(Path.GetTempPath(), "signed-contract.pdf");
    document.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "signed-contract.pdf");
});

app.Run();
using IronPdf;
using IronPdf.Signing;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/sign-with-certificate", (IWebHostEnvironment env) =>
{
    // Generate a PDF from HTML content
    var renderer = new ChromePdfRenderer();
    var document = renderer.RenderHtmlAsPdf("<h1>Contract Agreement</h1><p>Terms and conditions...</p>");

    // Locate the PFX certificate on the server
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");

    // Build the signature object
    var signature = new PdfSignature(certPath, "yourPassword")
    {
        SigningContact = "legal@yourcompany.com",
        SigningLocation = "Chicago, IL, USA",
        SigningReason = "Document Approval"
    };

    // Apply the signature and save
    document.Sign(signature);
    string outputPath = Path.Combine(Path.GetTempPath(), "signed-contract.pdf");
    document.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "signed-contract.pdf");
});

app.Run();
Imports IronPdf
Imports IronPdf.Signing
Imports Microsoft.AspNetCore.Mvc

Dim builder = WebApplication.CreateBuilder(args)
Dim app = builder.Build()

app.MapPost("/sign-with-certificate", Function(env As IWebHostEnvironment)
    ' Generate a PDF from HTML content
    Dim renderer = New ChromePdfRenderer()
    Dim document = renderer.RenderHtmlAsPdf("<h1>Contract Agreement</h1><p>Terms and conditions...</p>")

    ' Locate the PFX certificate on the server
    Dim certPath As String = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx")

    ' Build the signature object
    Dim signature = New PdfSignature(certPath, "yourPassword") With {
        .SigningContact = "legal@yourcompany.com",
        .SigningLocation = "Chicago, IL, USA",
        .SigningReason = "Document Approval"
    }

    ' Apply the signature and save
    document.Sign(signature)
    Dim outputPath As String = Path.Combine(Path.GetTempPath(), "signed-contract.pdf")
    document.SaveAs(outputPath)

    Return Results.File(outputPath, "application/pdf", "signed-contract.pdf")
End Function)

app.Run()
$vbLabelText   $csharpLabel

ChromePdfRenderer 将任何有效的 HTML 字符串或 URL 转换为 PDF。 PdfSignature 构造函数接受证书路径和密码,可选属性(SigningContactSigningLocationSigningReason)添加 PDF 查看器在签名面板中显示的元数据。 Sign 方法嵌入了加密签名,而 SaveAs 将签名文件写入磁盘。

从内存中返回已签名文件

如果您不想将临时文件写入磁盘,请将 PDF 保存到 MemoryStream 并直接从控制器操作返回它:

var stream = new MemoryStream();
document.SaveAs(stream);
stream.Position = 0;
return Results.File(stream, "application/pdf", "signed-contract.pdf");
var stream = new MemoryStream();
document.SaveAs(stream);
stream.Position = 0;
return Results.File(stream, "application/pdf", "signed-contract.pdf");
Dim stream As New MemoryStream()
document.SaveAs(stream)
stream.Position = 0
Return Results.File(stream, "application/pdf", "signed-contract.pdf")
$vbLabelText   $csharpLabel

这种方法适用于高吞吐量 API,因为临时文件管理会增加不必要的开销。

有关完整的属性参考,请参阅PdfSignature API 文档

如何在PDF中添加可见的签名图片?

加密签名可以保护文档的完整性,但在渲染后的 PDF 中是不可见的。 许多工作流程——尤其是涉及合同或信函的工作流程——还需要在纸上打印出可见的表示形式,例如扫描的手写签名或公司印章。

IronPDF 通过 LoadSignatureImageFromFile 方法支持此功能。 该方法接受图像路径、页面索引以及定义可见签名位置和尺寸的 IronSoftware.Drawing.Rectangle

using IronPdf;
using IronPdf.Signing;
using IronSoftware.Drawing;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/sign-with-visible-image", (IWebHostEnvironment env) =>
{
    // Load an existing PDF (for example, an invoice template)
    string pdfPath = Path.Combine(env.ContentRootPath, "Documents", "invoice.pdf");
    var document = PdfDocument.FromFile(pdfPath);

    // Paths to the certificate and the signature image
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");
    string imagePath = Path.Combine(env.ContentRootPath, "Images", "signature.png");

    // Define where the visible signature appears (x, y, width, height in points)
    var signatureArea = new Rectangle(50, 680, 200, 80);

    var signature = new PdfSignature(certPath, "yourPassword");
    signature.LoadSignatureImageFromFile(imagePath, pageIndex: 0, signatureArea);

    document.Sign(signature);
    string outputPath = Path.Combine(Path.GetTempPath(), "signed-invoice.pdf");
    document.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "signed-invoice.pdf");
});

app.Run();
using IronPdf;
using IronPdf.Signing;
using IronSoftware.Drawing;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/sign-with-visible-image", (IWebHostEnvironment env) =>
{
    // Load an existing PDF (for example, an invoice template)
    string pdfPath = Path.Combine(env.ContentRootPath, "Documents", "invoice.pdf");
    var document = PdfDocument.FromFile(pdfPath);

    // Paths to the certificate and the signature image
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");
    string imagePath = Path.Combine(env.ContentRootPath, "Images", "signature.png");

    // Define where the visible signature appears (x, y, width, height in points)
    var signatureArea = new Rectangle(50, 680, 200, 80);

    var signature = new PdfSignature(certPath, "yourPassword");
    signature.LoadSignatureImageFromFile(imagePath, pageIndex: 0, signatureArea);

    document.Sign(signature);
    string outputPath = Path.Combine(Path.GetTempPath(), "signed-invoice.pdf");
    document.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "signed-invoice.pdf");
});

app.Run();
Imports IronPdf
Imports IronPdf.Signing
Imports IronSoftware.Drawing
Imports Microsoft.AspNetCore.Mvc

Dim builder = WebApplication.CreateBuilder(args)
Dim app = builder.Build()

app.MapPost("/sign-with-visible-image", Function(env As IWebHostEnvironment)
    ' Load an existing PDF (for example, an invoice template)
    Dim pdfPath As String = Path.Combine(env.ContentRootPath, "Documents", "invoice.pdf")
    Dim document = PdfDocument.FromFile(pdfPath)

    ' Paths to the certificate and the signature image
    Dim certPath As String = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx")
    Dim imagePath As String = Path.Combine(env.ContentRootPath, "Images", "signature.png")

    ' Define where the visible signature appears (x, y, width, height in points)
    Dim signatureArea As New Rectangle(50, 680, 200, 80)

    Dim signature As New PdfSignature(certPath, "yourPassword")
    signature.LoadSignatureImageFromFile(imagePath, pageIndex:=0, signatureArea)

    document.Sign(signature)
    Dim outputPath As String = Path.Combine(Path.GetTempPath(), "signed-invoice.pdf")
    document.SaveAs(outputPath)

    Return Results.File(outputPath, "application/pdf", "signed-invoice.pdf")
End Function)

app.Run()
$vbLabelText   $csharpLabel

可见的签名图像会合成到您提供的指定页面上的坐标位置。加密签名会同时应用于整个文档,因此您只需一次操作即可获得安全性和视觉确认。

如果图像存在于内存中(例如,从数据库或云存储中获取),则改用 LoadSignatureImageFromStream。 如需深入了解视觉手语选项,请参阅PDF 手语使用指南

如何为外部签名者创建签名表单字段?

在某些工作流程中,文档由您的系统创建,但必须由外部方(客户、合作伙伴或监管机构)签署。 与其事先从对方处收集证明,不如在 PDF 中嵌入一个专门的签名表单字段,然后将文档发送给他们。 收件人使用 Adobe Acrobat Reader 或其他兼容的查看器打开 PDF 文件,点击签名字段,然后应用自己的证书或电子签名。

using IronPdf;
using IronPdf.Forms;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/generate-signable-form", (IWebHostEnvironment env) =>
{
    // Render the document that requires a client signature
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(@"
        <h1>Client Service Agreement</h1>
        <p>Please review the terms below and sign in the field provided.</p>
        <p>By signing, you confirm acceptance of all listed terms and conditions.</p>
    ");

    // Define the signature field: name, page, x, y, width, height (in points)
    var signatureField = new SignatureFormField(
        "ClientSignature",
        pageIndex: 0,
        x: 50,
        y: 600,
        width: 300,
        height: 100
    );

    pdf.Form.Add(signatureField);

    string outputPath = Path.Combine(Path.GetTempPath(), "client-agreement.pdf");
    pdf.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "client-agreement.pdf");
});

app.Run();
using IronPdf;
using IronPdf.Forms;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/generate-signable-form", (IWebHostEnvironment env) =>
{
    // Render the document that requires a client signature
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(@"
        <h1>Client Service Agreement</h1>
        <p>Please review the terms below and sign in the field provided.</p>
        <p>By signing, you confirm acceptance of all listed terms and conditions.</p>
    ");

    // Define the signature field: name, page, x, y, width, height (in points)
    var signatureField = new SignatureFormField(
        "ClientSignature",
        pageIndex: 0,
        x: 50,
        y: 600,
        width: 300,
        height: 100
    );

    pdf.Form.Add(signatureField);

    string outputPath = Path.Combine(Path.GetTempPath(), "client-agreement.pdf");
    pdf.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "client-agreement.pdf");
});

app.Run();
Imports IronPdf
Imports IronPdf.Forms
Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Hosting
Imports Microsoft.Extensions.Hosting

Dim builder = WebApplication.CreateBuilder(args)
Dim app = builder.Build()

app.MapGet("/generate-signable-form", Function(env As IWebHostEnvironment)
    ' Render the document that requires a client signature
    Dim renderer = New ChromePdfRenderer()
    Dim pdf = renderer.RenderHtmlAsPdf("
        <h1>Client Service Agreement</h1>
        <p>Please review the terms below and sign in the field provided.</p>
        <p>By signing, you confirm acceptance of all listed terms and conditions.</p>
    ")

    ' Define the signature field: name, page, x, y, width, height (in points)
    Dim signatureField = New SignatureFormField(
        "ClientSignature",
        pageIndex:=0,
        x:=50,
        y:=600,
        width:=300,
        height:=100
    )

    pdf.Form.Add(signatureField)

    Dim outputPath As String = Path.Combine(Path.GetTempPath(), "client-agreement.pdf")
    pdf.SaveAs(outputPath)

    Return Results.File(outputPath, "application/pdf", "client-agreement.pdf")
End Function)

app.Run()
$vbLabelText   $csharpLabel

SignatureFormField 构造函数参数直接映射到页面上字段的位置。 当收件人打开 PDF 文件时,他们会看到一个清晰标示的方框,用于填写他们的签名。 填妥的表格随后可以返回到您的系统中,您可以加载该表格,验证嵌入的签名,并将其存档。

有关 PDF 表单处理(包括读取已提交的表单数据)的更多信息,请参阅PDF 表单编辑指南

如何通过编程方式验证数字签名?

文件签署并寄回后,您可能需要核实签名是否仍然有效,以及文件是否已被更改。 IronPDF 通过 PdfDocument 对象公开签名验证:

using IronPdf;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/verify-signature", (IWebHostEnvironment env) =>
{
    string signedPath = Path.Combine(env.ContentRootPath, "Documents", "signed-contract.pdf");
    var document = PdfDocument.FromFile(signedPath);

    // Retrieve all embedded signatures
    var signatures = document.GetSignatures();

    foreach (var sig in signatures)
    {
        bool isValid = sig.VerifySignature();
        string status = isValid
            ? $"Valid -- signed by {sig.SignerName} on {sig.SigningTime:D}"
            : "INVALID -- document may have been tampered with";

        Console.WriteLine(status);
    }

    return Results.Ok(new { SignatureCount = signatures.Count });
});

app.Run();
using IronPdf;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/verify-signature", (IWebHostEnvironment env) =>
{
    string signedPath = Path.Combine(env.ContentRootPath, "Documents", "signed-contract.pdf");
    var document = PdfDocument.FromFile(signedPath);

    // Retrieve all embedded signatures
    var signatures = document.GetSignatures();

    foreach (var sig in signatures)
    {
        bool isValid = sig.VerifySignature();
        string status = isValid
            ? $"Valid -- signed by {sig.SignerName} on {sig.SigningTime:D}"
            : "INVALID -- document may have been tampered with";

        Console.WriteLine(status);
    }

    return Results.Ok(new { SignatureCount = signatures.Count });
});

app.Run();
Imports IronPdf
Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Hosting
Imports Microsoft.Extensions.Hosting

Dim builder = WebApplication.CreateBuilder(args)
Dim app = builder.Build()

app.MapGet("/verify-signature", Function(env As IWebHostEnvironment)
                                    Dim signedPath As String = Path.Combine(env.ContentRootPath, "Documents", "signed-contract.pdf")
                                    Dim document = PdfDocument.FromFile(signedPath)

                                    ' Retrieve all embedded signatures
                                    Dim signatures = document.GetSignatures()

                                    For Each sig In signatures
                                        Dim isValid As Boolean = sig.VerifySignature()
                                        Dim status As String = If(isValid,
                                            $"Valid -- signed by {sig.SignerName} on {sig.SigningTime:D}",
                                            "INVALID -- document may have been tampered with")

                                        Console.WriteLine(status)
                                    Next

                                    Return Results.Ok(New With {.SignatureCount = signatures.Count})
                                End Function)

app.Run()
$vbLabelText   $csharpLabel

GetSignatures() 返回 PDF 中嵌入的所有数字签名的列表。 每个 PdfDigitalSignature 对象都会公开 VerifySignature()、签名者姓名、签名时间戳和证书链。 这些信息足以构建审计跟踪或文档管理仪表板,以标记任何签名损坏或过期的 PDF 文件。

生产环境中如何处理证书管理?

在开发过程中,将 .pfx 文件存储在文件系统中是可行的,但不适合生产环境。 证书文件包含私钥,如果该文件被泄露,则使用该密钥签名的每个文档都将面临风险。

使用 Azure Key Vault

Azure Key Vault允许您存储和使用证书,而无需将私钥离开密钥库。 .NET SDK 提供了一个 CertificateClient,用于下载公共证书信息。 对于将私钥保存在密钥保管库中的实际签名操作,您可以使用Azure.Security.KeyVault.Keys包在服务器端执行加密操作。

使用环境变量和密钥

对于较小的项目,可以将证书以 Base64 编码字符串的形式存储在环境变量或ASP.NET Core Secrets Manager中,并在运行时对其进行解码:

string certBase64 = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT")
    ?? throw new InvalidOperationException("PDF_SIGNING_CERT environment variable is not set.");

byte[] certBytes = Convert.FromBase64String(certBase64);
string certPassword = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT_PASSWORD")
    ?? throw new InvalidOperationException("PDF_SIGNING_CERT_PASSWORD environment variable is not set.");

var signature = new PdfSignature(certBytes, certPassword);
string certBase64 = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT")
    ?? throw new InvalidOperationException("PDF_SIGNING_CERT environment variable is not set.");

byte[] certBytes = Convert.FromBase64String(certBase64);
string certPassword = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT_PASSWORD")
    ?? throw new InvalidOperationException("PDF_SIGNING_CERT_PASSWORD environment variable is not set.");

var signature = new PdfSignature(certBytes, certPassword);
Imports System

Dim certBase64 As String = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT")
If certBase64 Is Nothing Then
    Throw New InvalidOperationException("PDF_SIGNING_CERT environment variable is not set.")
End If

Dim certBytes As Byte() = Convert.FromBase64String(certBase64)
Dim certPassword As String = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT_PASSWORD")
If certPassword Is Nothing Then
    Throw New InvalidOperationException("PDF_SIGNING_CERT_PASSWORD environment variable is not set.")
End If

Dim signature = New PdfSignature(certBytes, certPassword)
$vbLabelText   $csharpLabel

这种模式使凭据脱离源代码控制,并使轮换变得简单——更新环境变量并重新启动服务。

如何高效地批量签署多个PDF文件?

当您需要一次性签署数十份或数百份文档时(例如,在月末签署整批发票),只需加载一次证书,并在所有文档中重复使用 PdfSignature 对象,即可减少开销:

using IronPdf;
using IronPdf.Signing;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/batch-sign", (IWebHostEnvironment env) =>
{
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");
    var signature = new PdfSignature(certPath, "yourPassword")
    {
        SigningReason = "Batch Invoice Approval"
    };

    string[] invoicePaths = Directory.GetFiles(
        Path.Combine(env.ContentRootPath, "Invoices"),
        "*.pdf"
    );

    string outputDir = Path.Combine(env.ContentRootPath, "Signed");
    Directory.CreateDirectory(outputDir);

    foreach (string invoicePath in invoicePaths)
    {
        var doc = PdfDocument.FromFile(invoicePath);
        doc.Sign(signature);
        string outputFile = Path.Combine(outputDir, Path.GetFileName(invoicePath));
        doc.SaveAs(outputFile);
    }

    return Results.Ok(new { SignedCount = invoicePaths.Length });
});

app.Run();
using IronPdf;
using IronPdf.Signing;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/batch-sign", (IWebHostEnvironment env) =>
{
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");
    var signature = new PdfSignature(certPath, "yourPassword")
    {
        SigningReason = "Batch Invoice Approval"
    };

    string[] invoicePaths = Directory.GetFiles(
        Path.Combine(env.ContentRootPath, "Invoices"),
        "*.pdf"
    );

    string outputDir = Path.Combine(env.ContentRootPath, "Signed");
    Directory.CreateDirectory(outputDir);

    foreach (string invoicePath in invoicePaths)
    {
        var doc = PdfDocument.FromFile(invoicePath);
        doc.Sign(signature);
        string outputFile = Path.Combine(outputDir, Path.GetFileName(invoicePath));
        doc.SaveAs(outputFile);
    }

    return Results.Ok(new { SignedCount = invoicePaths.Length });
});

app.Run();
Imports IronPdf
Imports IronPdf.Signing

Dim builder = WebApplication.CreateBuilder(args)
Dim app = builder.Build()

app.MapPost("/batch-sign", Function(env As IWebHostEnvironment)
    Dim certPath As String = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx")
    Dim signature As New PdfSignature(certPath, "yourPassword") With {
        .SigningReason = "Batch Invoice Approval"
    }

    Dim invoicePaths As String() = Directory.GetFiles(
        Path.Combine(env.ContentRootPath, "Invoices"),
        "*.pdf"
    )

    Dim outputDir As String = Path.Combine(env.ContentRootPath, "Signed")
    Directory.CreateDirectory(outputDir)

    For Each invoicePath As String In invoicePaths
        Dim doc = PdfDocument.FromFile(invoicePath)
        doc.Sign(signature)
        Dim outputFile As String = Path.Combine(outputDir, Path.GetFileName(invoicePath))
        doc.SaveAs(outputFile)
    Next

    Return Results.Ok(New With {.SignedCount = invoicePaths.Length})
End Function)

app.Run()
$vbLabelText   $csharpLabel

在循环之外创建一次 PdfSignature 对象意味着证书文件只会被读取和解析一次。 每次迭代都会加载、签名并保存一个单独的 PDF 文件。 对于非常大的批次,请考虑使用 Parallel.ForEach 并行处理文档 -- 当每个 PdfDocument 实例隔离到单个线程时,IronPDF 的签名操作是线程安全的。

如何排查常见的签名错误?

"未找到证书"或"密码无效"

使用 File.Exists(certPath) 仔细检查证书路径,然后再将其传递给 PdfSignature。 证书密码区分大小写,且必须完全匹配。 在开发过程中,通常会生成一个带有简单密码的自签名证书; 在生产环境中,将密码视为机密信息,并从机密管理器中加载。

PDF查看器中显示"签名无效"

Adobe Acrobat 中的"无效签名"警告通常意味着以下三种情况之一:(1)查看器的证书存储区不信任该证书;(2)签名后文档已被修改;(3)签名证书已过期。 对于生产环境,请从受信任的 CA 获取证书,并确保系统时钟同步。 对于开发工作,Adobe 提供了临时信任自签名证书的说明。

调用 Sign() 函数后出现"文档未签名"的错误。

调用 document.Sign(signature) 会将文档标记为待签名,但只有当您调用 SaveAs 或保存到流中时,签名才会最终完成。 请确保在 Sign 之后调用 save 方法,并验证输出文件路径是否可写。

有关完整的 API 详细信息和故障排除资源,请访问IronPDF 文档中心IronPDF 对象参考。 如果您需要帮助, IronPDF 支持页面会将您与工程团队联系起来。

下一步计划是什么?

一旦了解了三个核心操作,ASP.NET Core 中的数字 PDF 签名就变得非常简单:加载证书、调用 Sign 和保存结果。 IronPDF 处理繁重的加密工作,让您可以专注于应用程序的业务逻辑。

要继续构建您的文档工作流程,请探索以下相关主题:

-如何在 ASP.NET Core 中从 HTML 生成 PDF——大多数签名工作流程的基础 如何添加 PDF 密码和权限——结合签名和加密以实现最高安全性 如何合并和拆分 PDF 文件——在签署前组装多文档包 IronPDF 许可选项——选择适合您部署需求的方案

立即开始免费试用 IronPDF ,不到一小时即可生成您的第一个签名 PDF 文件。 如果您有任何疑问或遇到特殊情况, Iron Software 支持团队随时为您提供帮助,助您构建可靠且符合法律规定的文档签署工作流程。

常见问题解答

什么是 ASP.NET Core 中的数字签名?

ASP.NET Core 中的数字签名就像数字蜡封,用于验证 PDF 文档的真实性和完整性。它确保文档具有法律效力,未被篡改。

如何使用 IronPDF 为 PDF 文档添加数字签名?

您可以使用 IronPDF 为 PDF 文档添加数字签名,方法是加入证书并设置为签署文档,确保文档既安全又可验证。

为什么数字签名对我的商业文件很重要?

数字签名至关重要,因为它们可以验证合同或发票等文件的真实性和不变性,从而保护您的企业免受潜在的法律风险。

能否使用 IronPDF 在 PDF 中创建交互式表单字段?

是的,IronPDF 允许您在 PDF 中创建交互式表单字段,这可以增强 ASP.NET Core 应用程序中的用户交互并简化文档流程。

是否可以在 PDF 文档中添加可见签名?

是的,有了 IronPDF,您可以在 PDF 文档中添加可见签名,让收件人清楚地看到文档是经过安全签名和验证的。

哪些类型的证书可用于 PDF 中的数字签名?

您可以根据所需的安全和信任级别,在 PDF 中使用各种类型的证书进行数字签名,包括自签名证书和由受信任的证书颁发机构颁发的证书。

IronPDF 如何确保 PDF 文档未被篡改?

IronPDF 通过使用数字签名验证文档的完整性和真实性,确保 PDF 文档未被篡改,如果在签名后进行了更改,则会提醒收件人。

能否在 ASP.NET Core 应用程序中自动执行数字签名过程?

是的,您可以使用 IronPDF 在 ASP.NET Core 应用程序中自动执行数字签名流程,它允许批量处理并集成到现有工作流程中。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我