Skip to content

Commit 22aeaa0

Browse files
committed
Emit antiforgery only when streaming
1 parent 6b7447d commit 22aeaa0

File tree

2 files changed

+27
-10
lines changed

2 files changed

+27
-10
lines changed

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ namespace Microsoft.AspNetCore.Components.Endpoints.Forms;
1010
internal class EndpointAntiforgeryStateProvider(IAntiforgery antiforgery) : DefaultAntiforgeryStateProvider()
1111
{
1212
private HttpContext? _context;
13+
private bool _canGenerateToken;
1314

1415
internal void SetRequestContext(HttpContext context)
1516
{
1617
_context = context;
18+
_canGenerateToken = true;
1719
}
1820

1921
public override AntiforgeryRequestToken? GetAntiforgeryToken()
@@ -24,17 +26,23 @@ internal void SetRequestContext(HttpContext context)
2426
return _currentToken;
2527
}
2628

27-
// We already have a callback setup to generate the token when the response starts if needed.
28-
// If we need the tokens before we start streaming the response, we'll generate and store them;
29-
// otherwise we'll just retrieve them.
30-
// In case there are no tokens available, we are going to return null and no-op.
31-
var tokens = !_context.Response.HasStarted ? antiforgery.GetAndStoreTokens(_context) : antiforgery.GetTokens(_context);
32-
if (tokens.RequestToken is null)
29+
if (_currentToken == null && _canGenerateToken)
3330
{
34-
return null;
31+
// We already have a callback setup to generate the token when the response starts if needed.
32+
// If we need the tokens before we start streaming the response, we'll generate and store them;
33+
// otherwise we'll just retrieve them.
34+
// In case there are no tokens available, we are going to return null and no-op.
35+
var tokens = !_context.Response.HasStarted ? antiforgery.GetAndStoreTokens(_context) : antiforgery.GetTokens(_context);
36+
if (tokens.RequestToken is null)
37+
{
38+
return null;
39+
}
40+
41+
_currentToken = new AntiforgeryRequestToken(tokens.RequestToken, tokens.FormFieldName);
3542
}
3643

37-
_currentToken = new AntiforgeryRequestToken(tokens.RequestToken, tokens.FormFieldName);
3844
return _currentToken;
3945
}
46+
47+
internal void DisableTokenGeneration() => _canGenerateToken = false;
4048
}

src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
using System.Text;
77
using System.Text.Encodings.Web;
88
using Microsoft.AspNetCore.Antiforgery;
9+
using Microsoft.AspNetCore.Components.Endpoints.Forms;
910
using Microsoft.AspNetCore.Components.Endpoints.Rendering;
11+
using Microsoft.AspNetCore.Components.Forms;
1012
using Microsoft.AspNetCore.Components.Infrastructure;
1113
using Microsoft.AspNetCore.Diagnostics;
1214
using Microsoft.AspNetCore.Http;
@@ -135,8 +137,17 @@ await _renderer.InitializeStandardComponentServicesAsync(
135137
var bufferingFeature = context.Features.GetRequiredFeature<IHttpResponseBodyFeature>();
136138
bufferingFeature.DisableBuffering();
137139

140+
// Store the tokens if not emitted already in case we stream a form in the response.
141+
antiforgery!.GetAndStoreTokens(context);
142+
138143
context.Response.Headers.ContentEncoding = "identity";
139144
}
145+
else
146+
{
147+
// Disable token generation on EndpointAntiforgeryStateProvider if we are not streaming.
148+
var provider = (EndpointAntiforgeryStateProvider)context.RequestServices.GetRequiredService<AntiforgeryStateProvider>();
149+
provider.DisableTokenGeneration();
150+
}
140151

141152
// Importantly, we must not yield this thread (which holds exclusive access to the renderer sync context)
142153
// in between the first call to htmlContent.WriteTo and the point where we start listening for subsequent
@@ -146,8 +157,6 @@ await _renderer.InitializeStandardComponentServicesAsync(
146157

147158
if (!quiesceTask.IsCompletedSuccessfully)
148159
{
149-
// We need to ensure that the antiforgery tokens are generated and stored in the response
150-
antiforgery!.GetAndStoreTokens(context);
151160
await _renderer.SendStreamingUpdatesAsync(context, quiesceTask, bufferWriter);
152161
}
153162
else

0 commit comments

Comments
 (0)