Skip to content

Commit cdc96b0

Browse files
committed
Add antiforgery token to forms rendered interactively on the server
1 parent 52dcedf commit cdc96b0

File tree

6 files changed

+56
-5
lines changed

6 files changed

+56
-5
lines changed

src/Components/Endpoints/src/Forms/EndpointAntiforgeryStateProvider.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ internal void SetRequestContext(HttpContext context)
2020
{
2121
if (_context == null)
2222
{
23-
return null;
23+
// We're in an interactive context. Use the token persisted during static rendering.
24+
return base.GetAntiforgeryToken();
2425
}
2526

2627
// We already have a callback setup to generate the token when the response starts if needed.

src/Components/Shared/src/DefaultAntiforgeryStateProvider.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public DefaultAntiforgeryStateProvider(PersistentComponentState state)
2626
{
2727
state.PersistAsJson(PersistenceKey, GetAntiforgeryToken());
2828
return Task.CompletedTask;
29-
}, RenderMode.InteractiveWebAssembly);
29+
}, RenderMode.InteractiveAuto);
3030

3131
state.TryTakeFromJson(PersistenceKey, out _currentToken);
3232
}

src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs

+15
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,21 @@ public void CanUseAntiforgeryTokenInWasm()
909909
DispatchToFormCore(dispatchToForm);
910910
}
911911

912+
[Fact]
913+
public void CanUseAntiforgeryTokenWithServerInteractivity()
914+
{
915+
var dispatchToForm = new DispatchToForm(this)
916+
{
917+
Url = "forms/antiforgery-server-interactive",
918+
FormCssSelector = "form",
919+
InputFieldId = "value",
920+
InputFieldValue = "stranger",
921+
SuppressEnhancedNavigation = true,
922+
Ready = "really-ready",
923+
};
924+
DispatchToFormCore(dispatchToForm);
925+
}
926+
912927
[Theory]
913928
[InlineData(true)]
914929
[InlineData(false)]

src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs

+13-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using Components.TestServer.RazorComponents;
99
using Components.TestServer.RazorComponents.Pages.Forms;
1010
using Components.TestServer.Services;
11-
using Microsoft.AspNetCore.Components.WebAssembly.Server;
1211
using Microsoft.AspNetCore.Mvc;
1312

1413
namespace TestServer;
@@ -73,6 +72,19 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
7372
InteractiveStreamingRenderingComponent.MapEndpoints(endpoints);
7473

7574
MapEnhancedNavigationEndpoints(endpoints);
75+
76+
endpoints.MapPost("/verify-antiforgery", (
77+
[FromForm] string value,
78+
[FromForm(Name = "__RequestVerificationToken")] string csrfToken) =>
79+
{
80+
// We shouldn't get this far without a valid CSRF token, but we double check it's there.
81+
if (string.IsNullOrEmpty(csrfToken))
82+
{
83+
throw new Exception("Invalid POST to /verify-antiforgery!");
84+
}
85+
86+
return TypedResults.Text($"<p id='pass'>Hello {value}!</p>", "text/html");
87+
});
7688
});
7789
});
7890
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
@page "/forms/antiforgery-server-interactive"
2+
3+
@using Microsoft.AspNetCore.Components.Forms
4+
5+
@attribute [RenderModeInteractiveServer]
6+
7+
<h3>FormRenderedWithServerInteractivityCanUseAntiforgeryToken</h3>
8+
9+
<form action="verify-antiforgery" method="post" @formname="verify-antiforgery">
10+
<AntiforgeryToken />
11+
<input type="text" id="value" name="value" />
12+
<input id="send" name="send" type="submit" value="Send" />
13+
</form>
14+
15+
@if (HttpContext is null)
16+
{
17+
<p id="really-ready">Interactively rendered!</p>
18+
}
19+
20+
@code {
21+
[CascadingParameter]
22+
HttpContext? HttpContext { get; set; }
23+
}

src/Components/test/testassets/TestContentPackage/WasmFormComponent.razor

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
{
1717
@if (_succeeded)
1818
{
19-
<p id="pass">Posting the value succeded.</p>
19+
<p id="pass">Posting the value succeeded.</p>
2020
}
2121
else
2222
{
@@ -42,7 +42,7 @@ else
4242
if (OperatingSystem.IsBrowser())
4343
{
4444
var antiforgery = AntiforgeryState.GetAntiforgeryToken();
45-
_token = antiforgery.Value;
45+
_token = antiforgery.Value;
4646
}
4747
}
4848

0 commit comments

Comments
 (0)