Skip to content

Commit 678d949

Browse files
committed
Regression Fix
1 parent 22c504f commit 678d949

8 files changed

Lines changed: 88 additions & 41 deletions

File tree

‎samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub.EFCore/Components/Layout/MainLayout.razor.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private void HandleSignInClick()
5252

5353
if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase))
5454
{
55-
Nav.NavigateTo("/login?focus=1", replace: true, forceLoad: true);
55+
Nav.NavigateTo("/login?uauth_focus=1", replace: true, forceLoad: true);
5656
return;
5757
}
5858

‎samples/UAuthHub/CodeBeam.UltimateAuth.Sample.UAuthHub/Components/Layout/MainLayout.razor.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private void HandleSignInClick()
5252

5353
if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase))
5454
{
55-
Nav.NavigateTo("/login?focus=1", replace: true, forceLoad: true);
55+
Nav.NavigateTo("/login?uauth_focus=1", replace: true, forceLoad: true);
5656
return;
5757
}
5858

‎samples/blazor-server/CodeBeam.UltimateAuth.Sample.BlazorServer/Components/Layout/MainLayout.razor.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private void HandleSignInClick()
5252

5353
if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase))
5454
{
55-
Nav.NavigateTo("/login?focus=1", replace: true, forceLoad: true);
55+
Nav.NavigateTo("/login?uauth_focus=1", replace: true, forceLoad: true);
5656
return;
5757
}
5858

‎samples/blazor-standalone-wasm/CodeBeam.UltimateAuth.Sample.BlazorStandaloneWasm/Layout/MainLayout.razor.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private void HandleSignInClick()
5252

5353
if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase))
5454
{
55-
Nav.NavigateTo("/login?focus=1", replace: true, forceLoad: true);
55+
Nav.NavigateTo("/login?uauth_focus=1", replace: true, forceLoad: true);
5656
return;
5757
}
5858

‎samples/int-wasm/CodeBeam.UAuth.Sample.IntWasm/CodeBeam.UAuth.Sample.IntWasm.Client/Layout/MainLayout.razor.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private void HandleSignInClick()
5252

5353
if (uri.AbsolutePath.EndsWith("/login", StringComparison.OrdinalIgnoreCase))
5454
{
55-
Nav.NavigateTo("/login?focus=1", replace: true, forceLoad: true);
55+
Nav.NavigateTo("/login?uauth_focus=1", replace: true, forceLoad: true);
5656
return;
5757
}
5858

‎src/client/CodeBeam.UltimateAuth.Client.Blazor/Components/Base/UAuthComponentBase.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
5353
if (firstRender)
5454
{
5555
_rendered = true;
56-
EvaluateAuthorization();
56+
// Never call EvaluateAuthorization() here, because it breaks UAuthAuthorize attribute behavior.
5757
}
5858
}
5959

‎tests/CodeBeam.UltimateAuth.Tests.Unit/Client/Blazor/UAuthComponentBaseTests.cs‎

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -55,48 +55,21 @@ public void Render_WithoutAuthorizeAttribute_DoesNotCallUnauthorized()
5555
}
5656

5757
[Fact]
58-
public void Render_WithAuthorizeAttribute_WhenAnonymous_CallsUnauthorized()
58+
public void AuthStateCleared_WithRoleRequirement_WhenAnonymous_CallsUnauthorized_NotForbidden()
5959
{
6060
var state = UAuthState.Anonymous();
6161

62-
var cut =
63-
RenderWithState<AuthenticationRequiredComponent>(state);
64-
65-
var component = cut
66-
.FindComponent<AuthenticationRequiredComponent>()
67-
.Instance;
68-
69-
component.UnauthorizedCount.Should().Be(1);
70-
component.ForbiddenCount.Should().Be(0);
71-
}
72-
73-
[Fact]
74-
public void Render_WithRoleRequirement_WhenAnonymous_CallsUnauthorized_NotForbidden()
75-
{
76-
var state = UAuthState.Anonymous();
77-
78-
var cut =
79-
RenderWithState<AdminRequiredComponent>(state);
62+
var cut = RenderWithState<AdminRequiredComponent>(state);
8063

8164
var component = cut
8265
.FindComponent<AdminRequiredComponent>()
8366
.Instance;
8467

85-
component.UnauthorizedCount.Should().Be(1);
68+
// Initial render must not make a premature authorization decision.
69+
component.UnauthorizedCount.Should().Be(0);
8670
component.ForbiddenCount.Should().Be(0);
87-
}
8871

89-
[Fact]
90-
public void Render_WithPermissionRequirement_WhenAnonymous_CallsUnauthorized_NotForbidden()
91-
{
92-
var state = UAuthState.Anonymous();
93-
94-
var cut =
95-
RenderWithState<ReadUsersRequiredComponent>(state);
96-
97-
var component = cut
98-
.FindComponent<ReadUsersRequiredComponent>()
99-
.Instance;
72+
state.Clear();
10073

10174
component.UnauthorizedCount.Should().Be(1);
10275
component.ForbiddenCount.Should().Be(0);
@@ -146,17 +119,22 @@ public void Render_WithRequiredRole_WhenUserHasRole_DoesNotReject()
146119
}
147120

148121
[Fact]
149-
public void Render_WithRequiredRole_WhenUserDoesNotHaveRole_CallsForbidden()
122+
public void AuthStateChanged_WithRequiredRole_WhenUserDoesNotHaveRole_CallsForbidden()
150123
{
151124
var state = AuthenticatedState(
152-
roles: ["member"]);
125+
roles: ["User"]);
153126

154127
var cut = RenderWithState<AdminRequiredComponent>(state);
155128

156129
var component = cut
157130
.FindComponent<AdminRequiredComponent>()
158131
.Instance;
159132

133+
component.UnauthorizedCount.Should().Be(0);
134+
component.ForbiddenCount.Should().Be(0);
135+
136+
state.MarkStale();
137+
160138
component.UnauthorizedCount.Should().Be(0);
161139
component.ForbiddenCount.Should().Be(1);
162140
}
@@ -178,7 +156,7 @@ public void Render_WithRequiredPermission_WhenUserHasPermission_DoesNotReject()
178156
}
179157

180158
[Fact]
181-
public void Render_WithRequiredPermission_WhenUserDoesNotHavePermission_CallsForbidden()
159+
public void AuthStateChanged_WithRequiredPermission_WhenUserDoesNotHavePermission_CallsForbidden()
182160
{
183161
var state = AuthenticatedState(
184162
permissions: ["users.list"]);
@@ -189,6 +167,12 @@ public void Render_WithRequiredPermission_WhenUserDoesNotHavePermission_CallsFor
189167
.FindComponent<ReadUsersRequiredComponent>()
190168
.Instance;
191169

170+
// No premature decision during initial render.
171+
component.UnauthorizedCount.Should().Be(0);
172+
component.ForbiddenCount.Should().Be(0);
173+
174+
state.MarkStale();
175+
192176
component.UnauthorizedCount.Should().Be(0);
193177
component.ForbiddenCount.Should().Be(1);
194178
}
@@ -286,6 +270,39 @@ public void Dispose_UnsubscribesFromAuthState()
286270
.Should().Be(UAuthStateChangeReason.MarkedStale);
287271
}
288272

273+
[Fact]
274+
public void AuthStateCleared_WithAuthorizeAttribute_CallsUnauthorized()
275+
{
276+
var state = AuthenticatedState();
277+
278+
var cut = RenderWithState<AuthenticationRequiredComponent>(state);
279+
280+
var component = cut
281+
.FindComponent<AuthenticationRequiredComponent>()
282+
.Instance;
283+
284+
component.UnauthorizedCount.Should().Be(0);
285+
286+
state.Clear();
287+
288+
component.UnauthorizedCount.Should().Be(1);
289+
}
290+
291+
[Fact]
292+
public void InitialRender_WithAuthorizeAttribute_DoesNotEvaluateAuthorizationPrematurely()
293+
{
294+
var state = UAuthState.Anonymous();
295+
296+
var cut = RenderWithState<AuthenticationRequiredComponent>(state);
297+
298+
var component = cut
299+
.FindComponent<AuthenticationRequiredComponent>()
300+
.Instance;
301+
302+
component.UnauthorizedCount.Should().Be(0);
303+
component.ForbiddenCount.Should().Be(0);
304+
}
305+
289306
private IRenderedComponent<CascadingValue<UAuthState>> RenderWithState<TComponent>(UAuthState state) where TComponent : IComponent
290307
{
291308
return Render<CascadingValue<UAuthState>>(parameters =>

‎tests/CodeBeam.UltimateAuth.Tests.Unit/Client/Blazor/UAuthPageBaseTests.cs‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,36 @@ public void Rerender_DoesNotConsumeSamePayloadAgain()
430430
});
431431
}
432432

433+
[Fact]
434+
public void WithoutQueryCleanup_ParsedReturnUrlIsPreserved()
435+
{
436+
var state = UAuthState.Anonymous();
437+
438+
Navigate("/login?uauth_return_url=%2Fhome");
439+
440+
var cut = RenderPage<PersistentQueryPage>(state);
441+
442+
var page = cut
443+
.FindComponent<PersistentQueryPage>()
444+
.Instance;
445+
446+
page.ParsedReturnUrl.Should().Be("/home");
447+
448+
Nav.Uri.Should()
449+
.Be("http://localhost/login?uauth_return_url=%2Fhome");
450+
451+
cut.Render(parameters =>
452+
parameters
453+
.Add(x => x.Value, state)
454+
.AddChildContent<PersistentQueryPage>());
455+
456+
page = cut
457+
.FindComponent<PersistentQueryPage>()
458+
.Instance;
459+
460+
page.ParsedReturnUrl.Should().Be("/home");
461+
}
462+
433463
private void Navigate(string relativeUri)
434464
{
435465
Nav.NavigateTo(relativeUri);

0 commit comments

Comments
 (0)