|
| 1 | +--- |
| 2 | +title: Upload Files with Antiforgery Validation |
| 3 | +description: Learn how to setup the Telerik Blazor Upload to work with .NET controllers that use the ValidateAntiForgeryToken attribute. Configure Blazor apps with antiforgery validation. |
| 4 | +type: how-to |
| 5 | +page_title: How to Upload Files with Antiforgery Validation |
| 6 | +slug: upload-kb-validateantiforgerytoken |
| 7 | +position: |
| 8 | +tags: telerik, blazor, upload |
| 9 | +ticketid: 1626509, 1637325 |
| 10 | +res_type: kb |
| 11 | +--- |
| 12 | + |
| 13 | +## Environment |
| 14 | + |
| 15 | +<table> |
| 16 | + <tbody> |
| 17 | + <tr> |
| 18 | + <td>Product</td> |
| 19 | + <td>Upload for Blazor</td> |
| 20 | + </tr> |
| 21 | + </tbody> |
| 22 | +</table> |
| 23 | + |
| 24 | + |
| 25 | +## Description |
| 26 | + |
| 27 | +This KB article answers the following questions: |
| 28 | + |
| 29 | +* How to use the Telerik Blazor Upload component with controllers that are decorated with the `[ValidateAntiForgeryToken]` attribute? |
| 30 | +* How to upload files to controllers that require antiforgery validation? |
| 31 | +* How to set antiforgery tokens in the Upload's `OnUpload` and `OnRemove` events? |
| 32 | + |
| 33 | + |
| 34 | +## Solution |
| 35 | + |
| 36 | +Here are the suggested steps to configure .NET Core Blazor antiforgery validation and integrate it with the Telerik Upload component. |
| 37 | + |
| 38 | +1. Add services and configurations to `Program.cs`: |
| 39 | + * Add `builder.Services.AddRazorPages();` |
| 40 | + * Add `builder.Services.AddHttpContextAccessor();` |
| 41 | + * (optional) Add `builder.Services.AddAntiforgery()` with custom `HeaderName` or `FormFieldName`. |
| 42 | + * Verify that `app.UseAntiforgery();` is present. |
| 43 | + * Add `app.MapDefaultControllerRoute();` to configure routing. |
| 44 | +1. [Implement the `Save` and `Remove` controller methods]({%slug upload-overview%}#implement-controller-methods). |
| 45 | +1. Decorate the controller class or specific action methods with `[ValidateAntiForgeryToken]` |
| 46 | +1. Configure the Razor component, which contains the Telerik Blazor Upload: |
| 47 | + * Inject `AntiforgeryStateProvider` to use its `GetAntiforgeryToken()` method. |
| 48 | + * Inject `IAntiforgery` to use its `GetAndStoreTokens(httpContext)` method. |
| 49 | + * Inject `IHttpContextAccessor` to use its `HttpContext` property in the `GetAndStoreTokens()` method. |
| 50 | + * Execute `GetAndStoreTokens()` and/or `GetAntiforgeryToken()` in `OnInitialized` to obtain the required antiforgery information. |
| 51 | + * Add the required antiforgery information in the Upload component's [`OnUpload` and `OnRemove` event handlers]({%slug upload-events%}). |
| 52 | + |
| 53 | +The code snippets below assume that the application name is `BlazorAppName`. |
| 54 | + |
| 55 | +>caption Using Telerik Blazor Upload with antiforgery validation |
| 56 | +
|
| 57 | +<div class="skip-repl"></div> |
| 58 | + |
| 59 | +````Program.cs |
| 60 | +// This is not the complete Program.cs file, but only the relevant bits. |
| 61 | +
|
| 62 | +using Microsoft.AspNetCore.Http.Features; |
| 63 | +// Required by ValidateAntiForgeryTokenAttribute() |
| 64 | +using Microsoft.AspNetCore.Mvc; |
| 65 | +using Microsoft.AspNetCore.Server.Kestrel.Core; |
| 66 | + |
| 67 | +var builder = WebApplication.CreateBuilder(args); |
| 68 | + |
| 69 | +// ... |
| 70 | +
|
| 71 | +// Required by MapDefaultControllerRoute() |
| 72 | +builder.Services.AddRazorPages(); |
| 73 | + |
| 74 | +// Not necessary due to AddRazorPages() |
| 75 | +//builder.Services.AddControllersWithViews(options => |
| 76 | +//{ |
| 77 | +// options.Filters.Add(new ValidateAntiForgeryTokenAttribute()); |
| 78 | +//}); |
| 79 | +
|
| 80 | +// Required by Antiforgery.GetAndStoreTokens() in Razor components |
| 81 | +builder.Services.AddHttpContextAccessor(); |
| 82 | + |
| 83 | +// This statement and the custom names are optional. |
| 84 | +builder.Services.AddAntiforgery(options => { |
| 85 | + options.HeaderName = "X-CSRF-TOKEN-HEADERNAME"; |
| 86 | + options.FormFieldName = "X-CSRF-TOKEN-FORMFIELDNAME"; |
| 87 | +}); |
| 88 | + |
| 89 | +builder.Services.AddTelerikBlazor(); |
| 90 | + |
| 91 | +// ASP.NET Core Upload file size limit |
| 92 | +builder.Services.Configure<FormOptions>(options => |
| 93 | +{ |
| 94 | + options.MultipartBodyLengthLimit = 4_294_967_296; // 4 GB |
| 95 | +}); |
| 96 | +// Kestrel Upload file size limit |
| 97 | +builder.Services.Configure<KestrelServerOptions>(options => |
| 98 | +{ |
| 99 | + options.Limits.MaxRequestBodySize = 4_294_967_296; // 4 GB |
| 100 | +}); |
| 101 | + |
| 102 | +var app = builder.Build(); |
| 103 | + |
| 104 | +// ... |
| 105 | +
|
| 106 | +app.UseAntiforgery(); |
| 107 | + |
| 108 | +// Requires AddRazorPages() or AddControllersWithViews() |
| 109 | +app.MapDefaultControllerRoute(); |
| 110 | + |
| 111 | +// ... |
| 112 | +
|
| 113 | +app.Run(); |
| 114 | +```` |
| 115 | +````Razor |
| 116 | +@using Microsoft.AspNetCore.Antiforgery |
| 117 | +
|
| 118 | +@inject AntiforgeryStateProvider AfStateProvider |
| 119 | +@inject IAntiforgery Antiforgery |
| 120 | +@inject IHttpContextAccessor HttpContextAccessor |
| 121 | +@inject NavigationManager NavigationManager |
| 122 | +
|
| 123 | +<PageTitle>Home</PageTitle> |
| 124 | +
|
| 125 | +<TelerikUpload SaveUrl="@UploadSaveUrl" |
| 126 | + RemoveUrl="@UploadRemoveUrl" |
| 127 | + OnUpload="@OnUploadUpload" |
| 128 | + OnRemove="@OnUploadRemove" /> |
| 129 | +
|
| 130 | +@code { |
| 131 | + private string UploadSaveUrl => ToAbsoluteUrl("api/upload/save"); |
| 132 | + private string UploadRemoveUrl => ToAbsoluteUrl("api/upload/remove"); |
| 133 | +
|
| 134 | + private string? AntiforgeryHeaderName { get; set; } |
| 135 | + private string? AntiforgeryHeaderToken { get; set; } |
| 136 | + private string? AntiforgeryFormFieldName { get; set; } |
| 137 | + private string? AntiforgeryFormValue { get; set; } |
| 138 | +
|
| 139 | + private void OnUploadUpload(UploadEventArgs args) |
| 140 | + { |
| 141 | + // There is no need to post both antiforgery header and data. |
| 142 | + // Only one of them is enough. |
| 143 | +
|
| 144 | + args.RequestHeaders.Add(AntiforgeryHeaderName, AntiforgeryHeaderToken); |
| 145 | + args.RequestData.Add(AntiforgeryFormFieldName, AntiforgeryFormValue); |
| 146 | + } |
| 147 | +
|
| 148 | + private void OnUploadRemove(UploadEventArgs args) |
| 149 | + { |
| 150 | + // There is no need to post both antiforgery header and data. |
| 151 | + // Only one of them is enough. |
| 152 | +
|
| 153 | + args.RequestHeaders.Add(AntiforgeryHeaderName, AntiforgeryHeaderToken); |
| 154 | + args.RequestData.Add(AntiforgeryFormFieldName, AntiforgeryFormValue); |
| 155 | + } |
| 156 | +
|
| 157 | + protected override void OnInitialized() |
| 158 | + { |
| 159 | + // Obtain the antiforgery header name and value. |
| 160 | + if (HttpContextAccessor.HttpContext != null) |
| 161 | + { |
| 162 | + var afTokenSet = Antiforgery.GetAndStoreTokens(HttpContextAccessor.HttpContext); |
| 163 | + AntiforgeryHeaderName = afTokenSet.HeaderName; |
| 164 | + AntiforgeryHeaderToken = afTokenSet.RequestToken; |
| 165 | + } |
| 166 | +
|
| 167 | + // Obtain the antiforgery form field name and value. |
| 168 | + var afRequestToken = AfStateProvider.GetAntiforgeryToken(); |
| 169 | + if (afRequestToken != null) |
| 170 | + { |
| 171 | + AntiforgeryFormFieldName = afRequestToken.FormFieldName; |
| 172 | + AntiforgeryFormValue = afRequestToken.Value; |
| 173 | + } |
| 174 | +
|
| 175 | + base.OnInitialized(); |
| 176 | + } |
| 177 | +
|
| 178 | + private string ToAbsoluteUrl(string url) |
| 179 | + { |
| 180 | + return $"{NavigationManager.BaseUri}{url}"; |
| 181 | + } |
| 182 | +} |
| 183 | +```` |
| 184 | +````Controller |
| 185 | +using Microsoft.AspNetCore.Mvc; |
| 186 | +
|
| 187 | +namespace BlazorAppName.Controllers |
| 188 | +{ |
| 189 | + [ValidateAntiForgeryToken] |
| 190 | + [Route("api/[controller]/[action]")] |
| 191 | + public class UploadController : ControllerBase |
| 192 | + { |
| 193 | + public IWebHostEnvironment HostingEnvironment { get; set; } |
| 194 | +
|
| 195 | + public UploadController(IWebHostEnvironment hostingEnvironment) |
| 196 | + { |
| 197 | + HostingEnvironment = hostingEnvironment; |
| 198 | + } |
| 199 | +
|
| 200 | + [HttpPost] |
| 201 | + public async Task<IActionResult> Save(IFormFile files) |
| 202 | + { |
| 203 | + // Save the file... |
| 204 | +
|
| 205 | + return new EmptyResult(); |
| 206 | + } |
| 207 | +
|
| 208 | + [HttpPost] |
| 209 | + public async Task<IActionResult> Remove([FromForm] string files) |
| 210 | + { |
| 211 | + // Delete the file... |
| 212 | +
|
| 213 | + return new EmptyResult(); |
| 214 | + } |
| 215 | + } |
| 216 | +} |
| 217 | +```` |
| 218 | + |
| 219 | + |
| 220 | +## Disclaimer |
| 221 | + |
| 222 | +> 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](https://learn.microsoft.com/en-us/aspnet/core/blazor/security/). |
| 223 | +
|
| 224 | + |
| 225 | +## See Also |
| 226 | + |
| 227 | +* [Upload Overview]({%slug upload-overview%}) |
| 228 | +* [Upload Events]({%slug upload-events%}) |
| 229 | +* [Upload Troubleshooting]({%slug upload-troubleshooting%}) |
0 commit comments