Upload Files with Antiforgery Validation
Environment
Product | Upload for Blazor |
Description
This KB article answers the following questions:
- How to use the Telerik Blazor Upload component with controllers that are decorated with the
[ValidateAntiForgeryToken]
attribute? - How to upload files to controllers that require antiforgery validation?
- How to set antiforgery tokens in the Upload's
OnUpload
andOnRemove
events?
Solution
Here are the suggested steps to configure .NET Core Blazor antiforgery validation and integrate it with the Telerik Upload component.
- Add services and configurations to
Program.cs
:- Add
builder.Services.AddRazorPages();
- Add
builder.Services.AddHttpContextAccessor();
- (optional) Add
builder.Services.AddAntiforgery()
with customHeaderName
orFormFieldName
. - Verify that
app.UseAntiforgery();
is present. - Add
app.MapDefaultControllerRoute();
to configure routing.
- Add
-
Implement the
Save
andRemove
controller methods. - Decorate the controller class or specific action methods with
[ValidateAntiForgeryToken]
- Configure the Razor component, which contains the Telerik Blazor Upload:
- Inject
AntiforgeryStateProvider
to use itsGetAntiforgeryToken()
method. - Inject
IAntiforgery
to use itsGetAndStoreTokens(httpContext)
method. - Inject
IHttpContextAccessor
to use itsHttpContext
property in theGetAndStoreTokens()
method. - Execute
GetAndStoreTokens()
and/orGetAntiforgeryToken()
inOnInitialized
to obtain the required antiforgery information. - Add the required antiforgery information in the Upload component's
OnUpload
andOnRemove
event handlers.
- Inject
The code snippets below assume that the application name is BlazorAppName
.
// This is not the complete Program.cs file, but only the relevant bits.
using Microsoft.AspNetCore.Http.Features;
// Required by ValidateAntiForgeryTokenAttribute()
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Server.Kestrel.Core;
var builder = WebApplication.CreateBuilder(args);
// ...
// Required by MapDefaultControllerRoute()
builder.Services.AddRazorPages();
// Not necessary due to AddRazorPages()
//builder.Services.AddControllersWithViews(options =>
//{
// options.Filters.Add(new ValidateAntiForgeryTokenAttribute());
//});
// Required by Antiforgery.GetAndStoreTokens() in Razor components
builder.Services.AddHttpContextAccessor();
// This statement and the custom names are optional.
builder.Services.AddAntiforgery(options => {
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.FormFieldName = "X-CSRF-TOKEN-FORMFIELDNAME";
});
builder.Services.AddTelerikBlazor();
// ASP.NET Core Upload file size limit
builder.Services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = 4_294_967_296; // 4 GB
});
// Kestrel Upload file size limit
builder.Services.Configure<KestrelServerOptions>(options =>
{
options.Limits.MaxRequestBodySize = 4_294_967_296; // 4 GB
});
var app = builder.Build();
// ...
app.UseAntiforgery();
// Requires AddRazorPages() or AddControllersWithViews()
app.MapDefaultControllerRoute();
// ...
app.Run();
@using Microsoft.AspNetCore.Antiforgery
@inject AntiforgeryStateProvider AfStateProvider
@inject IAntiforgery Antiforgery
@inject IHttpContextAccessor HttpContextAccessor
@inject NavigationManager NavigationManager
<PageTitle>Home</PageTitle>
<TelerikUpload SaveUrl="@UploadSaveUrl"
RemoveUrl="@UploadRemoveUrl"
OnUpload="@OnUploadUpload"
OnRemove="@OnUploadRemove" />
@code {
private string UploadSaveUrl => ToAbsoluteUrl("api/upload/save");
private string UploadRemoveUrl => ToAbsoluteUrl("api/upload/remove");
private string? AntiforgeryHeaderName { get; set; }
private string? AntiforgeryHeaderToken { get; set; }
private string? AntiforgeryFormFieldName { get; set; }
private string? AntiforgeryFormValue { get; set; }
private void OnUploadUpload(UploadEventArgs args)
{
// There is no need to post both antiforgery header and data.
// Only one of them is enough.
args.RequestHeaders.Add(AntiforgeryHeaderName, AntiforgeryHeaderToken);
args.RequestData.Add(AntiforgeryFormFieldName, AntiforgeryFormValue);
}
private void OnUploadRemove(UploadEventArgs args)
{
// There is no need to post both antiforgery header and data.
// Only one of them is enough.
args.RequestHeaders.Add(AntiforgeryHeaderName, AntiforgeryHeaderToken);
args.RequestData.Add(AntiforgeryFormFieldName, AntiforgeryFormValue);
}
protected override void OnInitialized()
{
// Obtain the antiforgery header name and value.
if (HttpContextAccessor.HttpContext != null)
{
var afTokenSet = Antiforgery.GetAndStoreTokens(HttpContextAccessor.HttpContext);
AntiforgeryHeaderName = afTokenSet.HeaderName;
AntiforgeryHeaderToken = afTokenSet.RequestToken;
}
// Obtain the antiforgery form field name and value.
var afRequestToken = AfStateProvider.GetAntiforgeryToken();
if (afRequestToken != null)
{
AntiforgeryFormFieldName = afRequestToken.FormFieldName;
AntiforgeryFormValue = afRequestToken.Value;
}
base.OnInitialized();
}
private string ToAbsoluteUrl(string url)
{
return $"{NavigationManager.BaseUri}{url}";
}
}
using Microsoft.AspNetCore.Mvc;
namespace BlazorAppName.Controllers
{
[ValidateAntiForgeryToken]
[Route("api/[controller]/[action]")]
public class UploadController : ControllerBase
{
public IWebHostEnvironment HostingEnvironment { get; set; }
public UploadController(IWebHostEnvironment hostingEnvironment)
{
HostingEnvironment = hostingEnvironment;
}
[HttpPost]
public async Task<IActionResult> Save(IFormFile files)
{
// Save the file...
return new EmptyResult();
}
[HttpPost]
public async Task<IActionResult> Remove([FromForm] string files)
{
// Delete the file...
return new EmptyResult();
}
}
}
Disclaimer
This article contains code snippets and suggestions that relate to general .NET programming and antiforgery setup of a Blazor application. The provided implementation is just an example and is strictly outside the Telerik support scope. The primary resource for antiforgery configuration is the Microsoft documentation. See Blazor authentication and authorization.