Skip to content

Commit 531e681

Browse files
dimodiikoevska
andauthored
docs(upload): Add KB for Antiforgery integration (#1872)
* docs(upload): Add KB for Antiforgery integration * Update knowledge-base/upload-validateantiforgerytoken.md * Update components/upload/troubleshooting.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update components/upload/events.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]> * Update knowledge-base/upload-validateantiforgerytoken.md * improve bullet point --------- Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]>
1 parent 074523b commit 531e681

File tree

3 files changed

+235
-1
lines changed

3 files changed

+235
-1
lines changed

components/upload/events.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ If you cancel the event, the file upload will not start. If `AutoUpload="false"`
416416
Use the `OnUpload` and [`OnRemove`](#onremove) event handlers to send additional custom data and request headers to the server, together with the file. For example, the data may be related to:
417417

418418
* Authentication
419-
* CSRF cross-site anti forgery tokens
419+
* [CSRF/XSRF cross-site antiforgery tokens]({%slug upload-kb-validateantiforgerytoken%})
420420
* Any metadata related to the app business logic
421421

422422
To send **cookies** with the upload request, set the [`WithCredentials` component parameter]({%slug upload-overview%}#upload-parameters) to `true`.

components/upload/troubleshooting.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ The server does not return any response. The browser console shows connection er
5151
This means that the uploaded file size [exceeds the web server's maximum]({%slug upload-overview%}#large-file-uploads).
5252

5353

54+
## Antiforgery Validation Blocks the Upload Requests
55+
56+
If the upload controller is decorated with the `[ValidateAntiForgeryToken]` attribute, the Upload component must include antiforgery tokens in its upload and delete requests. Use the [`OnUpload` and `OnRemove`]({%slug upload-events%}) events to [add the required antiforgery tokens]({%slug upload-kb-validateantiforgerytoken%}).
57+
58+
5459
## See Also
5560

5661
* [How to implement Upload controller methods]({%slug upload-overview%}#implement-controller-methods)
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
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

Comments
 (0)