The HttpPost endpoint to which the signed document is forwarded can be in the same application or it can be in a completely different application. This tutorial will show you how to secure this endpoint through the use of custom filter attributes in ASP.NET Core.

Passing a Security Token

To provide an endpoint to forward the signature data and the signed document, the RedirectUrlAfterSignature property can be used. For protection of this endpoint, a custom filter can be implemented and a unique security token can be passed to the HttpPost method.

The following MVC Razor code shows how to integrate the Document Viewer and the security token that is passed in the RedirectUrlAfterSignature property.

@using TXTextControl.Web.MVC.DocumentViewer
@Html.TXTextControl().DocumentViewer(settings => {
settings.DocumentPath = "App_Data\\template.tx";
settings.SignatureSettings = new SignatureSettings() {
ShowSignatureBar = true,
OwnerName = "Josh Jackson",
SignerName = "Tim Typer",
SignerInitials = "TT",
UniqueId = "12345-12345-12345-12345",
RedirectUrlAfterSignature = this.Url.Action(
"HandleSignature",
"Signature",
new { secureID = "123" },
Context.Request.Scheme,
null),
SignatureBoxes = new SignatureBox[] {
new SignatureBox("txsign") { SigningRequired = true, Style = SignatureBox.SignatureBoxStyle.Signature },
new SignatureBox("txsigninit") { SigningRequired = true, Style = SignatureBox.SignatureBoxStyle.Initials }
}};
}).Render()
view raw test.cshtml hosted with ❤ by GitHub

The above code passes the security token "123" to the specified HandleSignature endpoint.

Controller Attributes

A custom ActionFilterAttribute CustomActionFilter is provided in the HandleSignature controller method.

[CustomActionFilter]
[HttpPost]
public IActionResult HandleSignature([FromBody] SignatureData data) {
byte[] bPDF;
// create temporary ServerTextControl
using (TXTextControl.ServerTextControl tx = new TXTextControl.ServerTextControl()) {
tx.Create();
// load the document
tx.Load(Convert.FromBase64String(data.SignedDocument.Document), TXTextControl.BinaryStreamType.InternalUnicodeFormat);
//FlattenFormFields(tx);
X509Certificate2 cert = new X509Certificate2("App_Data/textcontrolself.pfx", "123");
var signatureFields = new List<DigitalSignature>();
foreach (SignatureBox box in data.SignatureBoxes) {
signatureFields.Add(new DigitalSignature(cert, null, box.Name));
}
TXTextControl.SaveSettings saveSettings = new TXTextControl.SaveSettings() {
CreatorApplication = "Your Application",
SignatureFields = signatureFields.ToArray()
};
// store the PDF in the database or send it to the client
tx.Save(out bPDF, TXTextControl.BinaryStreamType.AdobePDFA, saveSettings);
// alternatively, save the PDF to a file
tx.Save("App_Data/signed.pdf", TXTextControl.StreamType.AdobePDFA, saveSettings);
}
// return any value to the client
return Ok();
}
view raw test.cs hosted with ❤ by GitHub

Filter Implementation

The custom filter implementation compares the security token and returns an error if the token is not valid.

public class CustomActionFilter : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.HttpContext.Request.Query["secureID"] != "123") {
filterContext.Result = new Microsoft.AspNetCore.Mvc.ContentResult() {
Content = "Access denied"
};
}
}
}
view raw test.cs hosted with ❤ by GitHub

In a real-world implementation, the security token would be uniquely generated server-side, stored in a database, and compared to the given parameter in the request.