diff --git a/src/Components/Components/src/PublicAPI.Unshipped.txt b/src/Components/Components/src/PublicAPI.Unshipped.txt index ce563e15a7cb..5eb52d2c330e 100644 --- a/src/Components/Components/src/PublicAPI.Unshipped.txt +++ b/src/Components/Components/src/PublicAPI.Unshipped.txt @@ -17,4 +17,3 @@ static Microsoft.AspNetCore.Components.Infrastructure.RegisterPersistentComponen static Microsoft.AspNetCore.Components.Infrastructure.ComponentsMetricsServiceCollectionExtensions.AddComponentsMetrics(Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.AspNetCore.Components.Infrastructure.ComponentsMetricsServiceCollectionExtensions.AddComponentsTracing(Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! static Microsoft.Extensions.DependencyInjection.SupplyParameterFromPersistentComponentStateProviderServiceCollectionExtensions.AddSupplyValueFromPersistentComponentStateProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! -virtual Microsoft.AspNetCore.Components.RenderTree.Renderer.SignalRendererToFinishRendering() -> void \ No newline at end of file diff --git a/src/Components/Components/src/RenderTree/Renderer.cs b/src/Components/Components/src/RenderTree/Renderer.cs index 177eccf9bf50..ce14869a5d45 100644 --- a/src/Components/Components/src/RenderTree/Renderer.cs +++ b/src/Components/Components/src/RenderTree/Renderer.cs @@ -49,7 +49,6 @@ public abstract partial class Renderer : IDisposable, IAsyncDisposable private bool _rendererIsDisposed; private bool _hotReloadInitialized; - private bool _rendererIsStopped; /// /// Allows the caller to handle exceptions from the SynchronizationContext when one is available. @@ -708,12 +707,6 @@ internal void AddToRenderQueue(int componentId, RenderFragment renderFragment) { Dispatcher.AssertAccess(); - if (_rendererIsStopped) - { - // Once we're stopped, we'll disregard further attempts to queue anything - return; - } - var componentState = GetOptionalComponentState(componentId); if (componentState == null) { @@ -780,22 +773,14 @@ private ComponentState GetRequiredRootComponentState(int componentId) return componentState; } - /// - /// Stop adding render requests to the render queue. - /// - protected virtual void SignalRendererToFinishRendering() - { - _rendererIsStopped = true; - } - /// /// Processes pending renders requests from components if there are any. /// protected virtual void ProcessPendingRender() { - if (_rendererIsDisposed || _rendererIsStopped) + if (_rendererIsDisposed) { - // Once we're disposed or stopped, we'll disregard further attempts to render anything + // Once we're disposed, we'll disregard further attempts to render anything return; } diff --git a/src/Components/Components/test/NavigationManagerTest.cs b/src/Components/Components/test/NavigationManagerTest.cs index 9b3763b45945..3f6e680d0c8b 100644 --- a/src/Components/Components/test/NavigationManagerTest.cs +++ b/src/Components/Components/test/NavigationManagerTest.cs @@ -1,7 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Diagnostics; +using System.Net.Http; +using System.Text; using Microsoft.AspNetCore.Components.Routing; using Microsoft.AspNetCore.InternalTesting; @@ -868,6 +871,22 @@ async ValueTask HandleLocationChanging(LocationChangingContext context) } } + [Fact] + public void OnNotFoundSubscriptionIsTriggeredWhenNotFoundCalled() + { + // Arrange + var baseUri = "scheme://host/"; + var testNavManager = new TestNavigationManager(baseUri); + bool notFoundTriggered = false; + testNavManager.OnNotFound += (sender, args) => notFoundTriggered = true; + + // Simulate a component triggered NotFound + testNavManager.NotFound(); + + // Assert + Assert.True(notFoundTriggered, "The OnNotFound event was not triggered as expected."); + } + private class TestNavigationManager : NavigationManager { public TestNavigationManager() diff --git a/src/Components/Endpoints/src/DependencyInjection/HttpNavigationManager.cs b/src/Components/Endpoints/src/DependencyInjection/HttpNavigationManager.cs index becfe7feeaa9..4585368b830a 100644 --- a/src/Components/Endpoints/src/DependencyInjection/HttpNavigationManager.cs +++ b/src/Components/Endpoints/src/DependencyInjection/HttpNavigationManager.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Components.Routing; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.AspNetCore.Components.Endpoints; @@ -9,6 +10,7 @@ internal sealed class HttpNavigationManager : NavigationManager, IHostEnvironmen { private const string _enableThrowNavigationException = "Microsoft.AspNetCore.Components.Endpoints.NavigationManager.EnableThrowNavigationException"; + [FeatureSwitchDefinition(_enableThrowNavigationException)] private static bool _throwNavigationException => AppContext.TryGetSwitch(_enableThrowNavigationException, out var switchValue) && switchValue; diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.EventDispatch.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.EventDispatch.cs index 8a1062a58d76..6af020fc847a 100644 --- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.EventDispatch.cs +++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.EventDispatch.cs @@ -97,7 +97,7 @@ private async Task SetNotFoundResponseAsync(string baseUri) // When the application triggers a NotFound event, we continue rendering the current batch. // However, after completing this batch, we do not want to process any further UI updates, // as we are going to return a 404 status and discard the UI updates generated so far. - SignalRendererToFinishRenderingAfterCurrentBatch(); + SignalRendererToFinishRendering(); } private async Task OnNavigateTo(string uri) diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs index e99574aa881e..1b2d4d9c94d0 100644 --- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs +++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs @@ -183,19 +183,12 @@ protected override void AddPendingTask(ComponentState? componentState, Task task base.AddPendingTask(componentState, task); } - private void SignalRendererToFinishRenderingAfterCurrentBatch() + private void SignalRendererToFinishRendering() { // sets a deferred stop on the renderer, which will have an effect after the current batch is completed _rendererIsStopped = true; } - protected override void SignalRendererToFinishRendering() - { - SignalRendererToFinishRenderingAfterCurrentBatch(); - // sets a hard stop on the renderer, which will have an effect immediately - base.SignalRendererToFinishRendering(); - } - protected override void ProcessPendingRender() { if (_rendererIsStopped) diff --git a/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs b/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs index 7bd648c783c1..bfb82e50d284 100644 --- a/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs +++ b/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs @@ -46,6 +46,21 @@ public EndpointHtmlRendererTest() renderer = GetEndpointHtmlRenderer(); } + [Fact] + public async Task DoesNotRenderChildAfterRendererStopped() + { + renderer.SignalRendererToFinishRendering(); + + var httpContext = GetHttpContext(); + var writer = new StringWriter(); + + var result = await renderer.PrerenderComponentAsync(httpContext, typeof(SimpleComponent), null, ParameterView.Empty); + await renderer.Dispatcher.InvokeAsync(() => result.WriteTo(writer, HtmlEncoder.Default)); + var content = writer.ToString(); + + Assert.DoesNotContain("Hello from SimpleComponent", content); + } + [Fact] public async Task CanRender_ParameterlessComponent_ClientMode() { @@ -1756,6 +1771,7 @@ private TestEndpointHtmlRenderer GetEndpointHtmlRenderer(IServiceProvider servic private class TestEndpointHtmlRenderer : EndpointHtmlRenderer { + private bool _rendererIsStopped = false; public TestEndpointHtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory) : base(serviceProvider, loggerFactory) { } @@ -1764,6 +1780,20 @@ internal int TestAssignRootComponentId(IComponent component) { return base.AssignRootComponentId(component); } + public void SignalRendererToFinishRendering() + { + // sets a deferred stop on the renderer, which will have an effect after the current batch is completed + _rendererIsStopped = true; + } + + protected override void ProcessPendingRender() + { + if (_rendererIsStopped) + { + return; + } + base.ProcessPendingRender(); + } } private HttpContext GetHttpContext(HttpContext context = null) diff --git a/src/Components/Server/src/Circuits/RemoteNavigationManager.cs b/src/Components/Server/src/Circuits/RemoteNavigationManager.cs index 0c38fcc8437b..b2d166f960a7 100644 --- a/src/Components/Server/src/Circuits/RemoteNavigationManager.cs +++ b/src/Components/Server/src/Circuits/RemoteNavigationManager.cs @@ -18,6 +18,8 @@ internal sealed partial class RemoteNavigationManager : NavigationManager, IHost private IJSRuntime _jsRuntime; private bool? _navigationLockStateBeforeJsRuntimeAttached; private const string _enableThrowNavigationException = "Microsoft.AspNetCore.Components.Endpoints.NavigationManager.EnableThrowNavigationException"; + + [FeatureSwitchDefinition("Microsoft.AspNetCore.Components.Endpoints.NavigationManager.EnableThrowNavigationException")] private static bool _throwNavigationException => AppContext.TryGetSwitch(_enableThrowNavigationException, out var switchValue) && switchValue; private Func? _onNavigateTo; diff --git a/src/Components/test/E2ETest/ServerExecutionTests/PrerenderingTest.cs b/src/Components/test/E2ETest/ServerExecutionTests/PrerenderingTest.cs index 9ab8248ec73f..3de6df8da5db 100644 --- a/src/Components/test/E2ETest/ServerExecutionTests/PrerenderingTest.cs +++ b/src/Components/test/E2ETest/ServerExecutionTests/PrerenderingTest.cs @@ -97,24 +97,6 @@ public void CanReadUrlHashOnlyOnceConnected() () => Browser.Exists(By.TagName("strong")).Text); } - [Theory] - [InlineData("base/relative", "prerendered/base/relative")] - [InlineData("/root/relative", "/root/relative")] - [InlineData("http://absolute/url", "http://absolute/url")] - public async Task CanRedirectDuringPrerendering(string destinationParam, string expectedRedirectionLocation) - { - var requestUri = new Uri( - _serverFixture.RootUri, - "prerendered/prerendered-redirection?destination=" + destinationParam); - - var httpClient = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false }); - var response = await httpClient.GetAsync(requestUri); - - var expectedUri = new Uri(_serverFixture.RootUri, expectedRedirectionLocation); - Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); - Assert.Equal(expectedUri, response.Headers.Location); - } - [Theory] [InlineData(null, null)] [InlineData(null, "Bert")] diff --git a/src/Components/test/E2ETest/ServerRenderingTests/RenderingTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/RenderingTest.cs index 16a1387feb89..8232098d8a78 100644 --- a/src/Components/test/E2ETest/ServerRenderingTests/RenderingTest.cs +++ b/src/Components/test/E2ETest/ServerRenderingTests/RenderingTest.cs @@ -66,4 +66,53 @@ public void PostRequestRendersEndStateOfComponentsOnSSRPage() Browser.Equal("loaded child", () => Browser.Exists(By.Id("child")).Text); } + + [Theory] + [InlineData(false, "ServerPrerendered", true)] + [InlineData(false, "ServerPrerendered", false)] + [InlineData(true, "ServerPrerendered", false)] + [InlineData(true, "ServerNonPrerendered", false)] + [InlineData(true, "WebAssemblyPrerendered", false)] + [InlineData(true, "WebAssemblyNonPrerendered", false)] + public async Task RenderBatchQueuedAfterRedirectionIsNotProcessed(bool redirect, string renderMode, bool throwSync) + { + string relativeUri = $"subdir/stopping-renderer?renderMode={renderMode}"; + if (redirect) + { + relativeUri += $"&destination=redirect"; + } + + // async operation forces the next render batch + if (throwSync) + { + relativeUri += $"&delay=0"; + } + else + { + relativeUri += $"&delay=1"; + } + + var requestUri = new Uri(_serverFixture.RootUri, relativeUri); + var httpClient = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false }); + var response = await httpClient.GetAsync(requestUri); + + if (redirect) + { + var expectedUri = new Uri(_serverFixture.RootUri, "subdir/redirect"); + Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); + Assert.Equal(expectedUri, response.Headers.Location); + } + else + { + // the status code cannot be changed after it got set, so async throwing returns OK + if (throwSync) + { + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + } + else + { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + } + } } diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Components/InteractiveStreamingRenderingComponent.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Components/InteractiveStreamingRenderingComponent.razor index de9d5114a204..605941be0f38 100644 --- a/src/Components/test/testassets/Components.TestServer/RazorComponents/Components/InteractiveStreamingRenderingComponent.razor +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Components/InteractiveStreamingRenderingComponent.razor @@ -59,7 +59,7 @@ else object key = DisableKeys ? null : counter.Id; RenderMode.InteractiveServer, - RenderModeId.ServerNonPrerendered => new InteractiveServerRenderMode(false), - RenderModeId.WebAssemblyPrerendered => RenderMode.InteractiveWebAssembly, - RenderModeId.WebAssemblyNonPrerendered => new InteractiveWebAssemblyRenderMode(false), - RenderModeId.AutoPrerendered => RenderMode.InteractiveAuto, - RenderModeId.AutoNonPrerendered => new InteractiveAutoRenderMode(false), - _ => throw new InvalidOperationException($"Unknown render mode: {renderMode}"), - }; - } - - private enum RenderModeId - { - ServerPrerendered = 0, - ServerNonPrerendered = 1, - WebAssemblyPrerendered = 2, - WebAssemblyNonPrerendered = 3, - AutoPrerendered = 4, - AutoNonPrerendered = 5, - } - private record struct CounterInfo(int Id, int IncrementAmount, RenderModeId RenderModeId); private record ComponentState(ImmutableArray Counters, int NextCounterId) diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Rendering/AsyncComponent.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Rendering/AsyncComponent.razor new file mode 100644 index 000000000000..ead21ed17d84 --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Rendering/AsyncComponent.razor @@ -0,0 +1,28 @@ +@if(throwException) +{ + throw new InvalidOperationException("Child component UI exception: redirection should have stopped renderer."); +} + +@code { + [Parameter] + public int Delay { get; set; } + + private bool throwException { get; set; } + + private string message = string.Empty; + + protected override async Task OnInitializedAsync() + { + await Task.Yield(); + _ = ScheduleRenderingExceptionAfterDelay(); + } + + private async Task ScheduleRenderingExceptionAfterDelay() + { + // This update should not happen if the renderer is stopped + await Task.Delay(Delay); + throwException = true; + StateHasChanged(); + } +} + diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Rendering/StoppingRenderer.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Rendering/StoppingRenderer.razor new file mode 100644 index 000000000000..e60fc672ed6b --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Rendering/StoppingRenderer.razor @@ -0,0 +1,27 @@ +@page "/stopping-renderer" +@inject NavigationManager NavigationManager + +

Parent content

+ + +@code { + [Parameter, SupplyParameterFromQuery(Name = "destination")] + public string Destination { get; set; } = string.Empty; + + [Parameter, SupplyParameterFromQuery(Name = "renderMode")] + public string? RenderModeStr { get; set; } + + [Parameter, SupplyParameterFromQuery(Name = "delay")] + public int Delay { get; set; } + + private RenderModeId CurrentRenderMode => RenderModeHelper.ParseRenderMode(RenderModeStr); + + protected override Task OnInitializedAsync() + { + if (!string.IsNullOrEmpty(Destination)) + { + NavigationManager.NavigateTo(Destination); + } + return Task.CompletedTask; + } +} diff --git a/src/Components/test/testassets/Components.TestServer/RenderModeHelper.cs b/src/Components/test/testassets/Components.TestServer/RenderModeHelper.cs new file mode 100644 index 000000000000..ab1285699691 --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RenderModeHelper.cs @@ -0,0 +1,46 @@ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; + +namespace TestServer; + +public static class RenderModeHelper +{ + public static IComponentRenderMode GetRenderMode(RenderModeId renderMode) + { + return renderMode switch + { + RenderModeId.ServerPrerendered => RenderMode.InteractiveServer, + RenderModeId.ServerNonPrerendered => new InteractiveServerRenderMode(false), + RenderModeId.WebAssemblyPrerendered => RenderMode.InteractiveWebAssembly, + RenderModeId.WebAssemblyNonPrerendered => new InteractiveWebAssemblyRenderMode(false), + RenderModeId.AutoPrerendered => RenderMode.InteractiveAuto, + RenderModeId.AutoNonPrerendered => new InteractiveAutoRenderMode(false), + _ => throw new InvalidOperationException($"Unknown render mode: {renderMode}"), + }; + } + + public static RenderModeId ParseRenderMode(string? renderModeStr) + { + if (!string.IsNullOrEmpty(renderModeStr) && + Enum.TryParse(renderModeStr, ignoreCase: true, out var result)) + { + return result; + } + return RenderModeId.AutoNonPrerendered; + } + +} + +public enum RenderModeId +{ + ServerPrerendered = 0, + ServerNonPrerendered = 1, + WebAssemblyPrerendered = 2, + WebAssemblyNonPrerendered = 3, + AutoPrerendered = 4, + AutoNonPrerendered = 5, +} diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/IdentityRedirectManager.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/IdentityRedirectManager.cs index da85e6efd46d..00734c65c714 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/IdentityRedirectManager.cs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/IdentityRedirectManager.cs @@ -1,5 +1,6 @@ -using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Identity; +using BlazorWeb_CSharp.Data; namespace BlazorWeb_CSharp.Components.Account; @@ -15,7 +16,6 @@ internal sealed class IdentityRedirectManager(NavigationManager navigationManage MaxAge = TimeSpan.FromSeconds(5), }; - [DoesNotReturn] public void RedirectTo(string? uri) { uri ??= ""; @@ -26,13 +26,9 @@ public void RedirectTo(string? uri) uri = navigationManager.ToBaseRelativePath(uri); } - // During static rendering, NavigateTo throws a NavigationException which is handled by the framework as a redirect. - // So as long as this is called from a statically rendered Identity component, the InvalidOperationException is never thrown. navigationManager.NavigateTo(uri); - throw new InvalidOperationException($"{nameof(IdentityRedirectManager)} can only be used during static rendering."); } - [DoesNotReturn] public void RedirectTo(string uri, Dictionary queryParameters) { var uriWithoutQuery = navigationManager.ToAbsoluteUri(uri).GetLeftPart(UriPartial.Path); @@ -40,7 +36,6 @@ public void RedirectTo(string uri, Dictionary queryParameters) RedirectTo(newUri); } - [DoesNotReturn] public void RedirectToWithStatus(string uri, string message, HttpContext context) { context.Response.Cookies.Append(StatusCookieName, message, StatusCookieBuilder.Build(context)); @@ -49,10 +44,11 @@ public void RedirectToWithStatus(string uri, string message, HttpContext context private string CurrentPath => navigationManager.ToAbsoluteUri(navigationManager.Uri).GetLeftPart(UriPartial.Path); - [DoesNotReturn] public void RedirectToCurrentPage() => RedirectTo(CurrentPath); - [DoesNotReturn] public void RedirectToCurrentPageWithStatus(string message, HttpContext context) => RedirectToWithStatus(CurrentPath, message, context); + + public void RedirectToInvalidUser(UserManager userManager, HttpContext context) + => RedirectToWithStatus("Account/InvalidUser", $"Error: Unable to load user with ID '{userManager.GetUserId(context.User)}'.", context); } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/IdentityUserAccessor.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/IdentityUserAccessor.cs deleted file mode 100644 index 86e027c0b6ee..000000000000 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/IdentityUserAccessor.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.AspNetCore.Identity; -using BlazorWeb_CSharp.Data; - -namespace BlazorWeb_CSharp.Components.Account; - -internal sealed class IdentityUserAccessor(UserManager userManager, IdentityRedirectManager redirectManager) -{ - public async Task GetRequiredUserAsync(HttpContext context) - { - var user = await userManager.GetUserAsync(context.User); - - if (user is null) - { - redirectManager.RedirectToWithStatus("Account/InvalidUser", $"Error: Unable to load user with ID '{userManager.GetUserId(context.User)}'.", context); - } - - return user; - } -} diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ConfirmEmail.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ConfirmEmail.razor index 830ee204c824..4254c0e65bae 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ConfirmEmail.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ConfirmEmail.razor @@ -30,6 +30,7 @@ if (UserId is null || Code is null) { RedirectManager.RedirectTo(""); + return; } var user = await UserManager.FindByIdAsync(UserId); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ConfirmEmailChange.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ConfirmEmailChange.razor index 478a810defc9..a1547b6fa41c 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ConfirmEmailChange.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ConfirmEmailChange.razor @@ -36,6 +36,7 @@ { RedirectManager.RedirectToWithStatus( "Account/Login", "Error: Invalid email change confirmation link.", HttpContext); + return; } var user = await UserManager.FindByIdAsync(UserId); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ExternalLogin.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ExternalLogin.razor index 0e5200ecb4e5..611b3448d7f6 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ExternalLogin.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ExternalLogin.razor @@ -101,6 +101,7 @@ if (externalLoginInfo is null) { RedirectManager.RedirectToWithStatus("Account/Login", "Error loading external login information.", HttpContext); + return; } // Sign in the user with this external login provider if the user already has a login. @@ -121,6 +122,7 @@ else if (result.IsLockedOut) { RedirectManager.RedirectTo("Account/Lockout"); + return; } // If the user does not have an account, then ask the user to create an account. @@ -135,6 +137,7 @@ if (externalLoginInfo is null) { RedirectManager.RedirectToWithStatus("Account/Login", "Error loading external login information during confirmation.", HttpContext); + return; } var emailStore = GetEmailStore(); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ForgotPassword.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ForgotPassword.razor index efe20b0f5639..1ab1bfa5fcb0 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ForgotPassword.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ForgotPassword.razor @@ -44,6 +44,7 @@ { // Don't reveal that the user does not exist or is not confirmed RedirectManager.RedirectTo("Account/ForgotPasswordConfirmation"); + return; } // For more information on how to enable account confirmation and password reset please diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ChangePassword.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ChangePassword.razor index dc21755a47b0..1764bde9919f 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ChangePassword.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ChangePassword.razor @@ -6,7 +6,7 @@ @inject UserManager UserManager @inject SignInManager SignInManager -@inject IdentityUserAccessor UserAccessor +@inject RedirectManager RedirectManager @inject IdentityRedirectManager RedirectManager @inject ILogger Logger @@ -41,7 +41,7 @@ @code { private string? message; - private ApplicationUser user = default!; + private ApplicationUser? user; private bool hasPassword; [CascadingParameter] @@ -52,7 +52,13 @@ protected override async Task OnInitializedAsync() { - user = await UserAccessor.GetRequiredUserAsync(HttpContext); + user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + hasPassword = await UserManager.HasPasswordAsync(user); if (!hasPassword) { @@ -62,6 +68,12 @@ private async Task OnValidSubmitAsync() { + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + var changePasswordResult = await UserManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword); if (!changePasswordResult.Succeeded) { diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/DeletePersonalData.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/DeletePersonalData.razor index d7bfb84d491b..12dcd63bd78a 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/DeletePersonalData.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/DeletePersonalData.razor @@ -6,7 +6,6 @@ @inject UserManager UserManager @inject SignInManager SignInManager -@inject IdentityUserAccessor UserAccessor @inject IdentityRedirectManager RedirectManager @inject ILogger Logger @@ -40,7 +39,7 @@ @code { private string? message; - private ApplicationUser user = default!; + private ApplicationUser? user; private bool requirePassword; [CascadingParameter] @@ -52,12 +51,23 @@ protected override async Task OnInitializedAsync() { Input ??= new(); - user = await UserAccessor.GetRequiredUserAsync(HttpContext); + user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } requirePassword = await UserManager.HasPasswordAsync(user); } private async Task OnValidSubmitAsync() { + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + if (requirePassword && !await UserManager.CheckPasswordAsync(user, Input.Password)) { message = "Error: Incorrect password."; diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Disable2fa.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Disable2fa.razor index d3969f457c9c..a539c533fa19 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Disable2fa.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Disable2fa.razor @@ -4,7 +4,6 @@ @using BlazorWeb_CSharp.Data @inject UserManager UserManager -@inject IdentityUserAccessor UserAccessor @inject IdentityRedirectManager RedirectManager @inject ILogger Logger @@ -31,14 +30,19 @@ @code { - private ApplicationUser user = default!; + private ApplicationUser? user; [CascadingParameter] private HttpContext HttpContext { get; set; } = default!; protected override async Task OnInitializedAsync() { - user = await UserAccessor.GetRequiredUserAsync(HttpContext); + user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } if (HttpMethods.IsGet(HttpContext.Request.Method) && !await UserManager.GetTwoFactorEnabledAsync(user)) { @@ -48,6 +52,12 @@ private async Task OnSubmitAsync() { + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + var disable2faResult = await UserManager.SetTwoFactorEnabledAsync(user, false); if (!disable2faResult.Succeeded) { diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Email.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Email.razor index c8b1518061ae..5cbfdcb75024 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Email.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Email.razor @@ -9,8 +9,8 @@ @inject UserManager UserManager @inject IEmailSender EmailSender -@inject IdentityUserAccessor UserAccessor @inject NavigationManager NavigationManager +@inject IdentityRedirectManager RedirectManager Manage email @@ -55,7 +55,7 @@ @code { private string? message; - private ApplicationUser user = default!; + private ApplicationUser? user; private string? email; private bool isEmailConfirmed; @@ -67,7 +67,13 @@ protected override async Task OnInitializedAsync() { - user = await UserAccessor.GetRequiredUserAsync(HttpContext); + user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + email = await UserManager.GetEmailAsync(user); isEmailConfirmed = await UserManager.IsEmailConfirmedAsync(user); @@ -82,6 +88,12 @@ return; } + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + var userId = await UserManager.GetUserIdAsync(user); var code = await UserManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); @@ -101,6 +113,12 @@ return; } + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + var userId = await UserManager.GetUserIdAsync(user); var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/EnableAuthenticator.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/EnableAuthenticator.razor index 1872e9e6c83b..be8c1429e18b 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/EnableAuthenticator.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/EnableAuthenticator.razor @@ -8,7 +8,6 @@ @using BlazorWeb_CSharp.Data @inject UserManager UserManager -@inject IdentityUserAccessor UserAccessor @inject UrlEncoder UrlEncoder @inject IdentityRedirectManager RedirectManager @inject ILogger Logger @@ -70,7 +69,7 @@ else private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6"; private string? message; - private ApplicationUser user = default!; + private ApplicationUser? user; private string? sharedKey; private string? authenticatorUri; private IEnumerable? recoveryCodes; @@ -83,13 +82,22 @@ else protected override async Task OnInitializedAsync() { - user = await UserAccessor.GetRequiredUserAsync(HttpContext); - - await LoadSharedKeyAndQrCodeUriAsync(user); + user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } } private async Task OnValidSubmitAsync() { + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + // Strip spaces and hyphens var verificationCode = Input.Code.Replace(" ", string.Empty).Replace("-", string.Empty); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ExternalLogins.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ExternalLogins.razor index 25a6b27926a0..00794aa25f93 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ExternalLogins.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ExternalLogins.razor @@ -6,7 +6,6 @@ @inject UserManager UserManager @inject SignInManager SignInManager -@inject IdentityUserAccessor UserAccessor @inject IUserStore UserStore @inject IdentityRedirectManager RedirectManager @@ -66,7 +65,7 @@ @code { public const string LinkLoginCallbackAction = "LinkLoginCallback"; - private ApplicationUser user = default!; + private ApplicationUser? user; private IList? currentLogins; private IList? otherLogins; private bool showRemoveButton; @@ -85,7 +84,13 @@ protected override async Task OnInitializedAsync() { - user = await UserAccessor.GetRequiredUserAsync(HttpContext); + user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + currentLogins = await UserManager.GetLoginsAsync(user); otherLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()) .Where(auth => currentLogins.All(ul => auth.Name != ul.LoginProvider)) @@ -107,6 +112,12 @@ private async Task OnSubmitAsync() { + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + var result = await UserManager.RemoveLoginAsync(user, LoginProvider!, ProviderKey!); if (!result.Succeeded) { @@ -119,11 +130,18 @@ private async Task OnGetLinkLoginCallbackAsync() { + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + var userId = await UserManager.GetUserIdAsync(user); var info = await SignInManager.GetExternalLoginInfoAsync(userId); if (info is null) { RedirectManager.RedirectToCurrentPageWithStatus("Error: Could not load external login info.", HttpContext); + return; } var result = await UserManager.AddLoginAsync(user, info); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/GenerateRecoveryCodes.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/GenerateRecoveryCodes.razor index c63c765ab887..3e62899c0a14 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/GenerateRecoveryCodes.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/GenerateRecoveryCodes.razor @@ -4,7 +4,6 @@ @using BlazorWeb_CSharp.Data @inject UserManager UserManager -@inject IdentityUserAccessor UserAccessor @inject IdentityRedirectManager RedirectManager @inject ILogger Logger @@ -40,7 +39,7 @@ else @code { private string? message; - private ApplicationUser user = default!; + private ApplicationUser? user; private IEnumerable? recoveryCodes; [CascadingParameter] @@ -48,7 +47,12 @@ else protected override async Task OnInitializedAsync() { - user = await UserAccessor.GetRequiredUserAsync(HttpContext); + user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } var isTwoFactorEnabled = await UserManager.GetTwoFactorEnabledAsync(user); if (!isTwoFactorEnabled) @@ -59,6 +63,12 @@ else private async Task OnSubmitAsync() { + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + var userId = await UserManager.GetUserIdAsync(user); recoveryCodes = await UserManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); message = "You have generated new recovery codes."; diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Index.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Index.razor index bff831a1d852..b5ca1361af4e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Index.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/Index.razor @@ -6,7 +6,6 @@ @inject UserManager UserManager @inject SignInManager SignInManager -@inject IdentityUserAccessor UserAccessor @inject IdentityRedirectManager RedirectManager Profile @@ -34,7 +33,7 @@ @code { - private ApplicationUser user = default!; + private ApplicationUser? user; private string? username; private string? phoneNumber; @@ -46,7 +45,13 @@ protected override async Task OnInitializedAsync() { - user = await UserAccessor.GetRequiredUserAsync(HttpContext); + user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + username = await UserManager.GetUserNameAsync(user); phoneNumber = await UserManager.GetPhoneNumberAsync(user); @@ -55,6 +60,12 @@ private async Task OnValidSubmitAsync() { + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + if (Input.PhoneNumber != phoneNumber) { var setPhoneResult = await UserManager.SetPhoneNumberAsync(user, Input.PhoneNumber); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/PersonalData.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/PersonalData.razor index 851eb54c8820..42dd6d52ada3 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/PersonalData.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/PersonalData.razor @@ -1,6 +1,10 @@ @page "/Account/Manage/PersonalData" -@inject IdentityUserAccessor UserAccessor +@using Microsoft.AspNetCore.Identity +@using BlazorWeb_CSharp.Data + +@inject UserManager UserManager +@inject IdentityRedirectManager RedirectManager Personal Data @@ -29,6 +33,11 @@ protected override async Task OnInitializedAsync() { - _ = await UserAccessor.GetRequiredUserAsync(HttpContext); + var user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } } } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ResetAuthenticator.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ResetAuthenticator.razor index c12e38094f76..c087a5eb6797 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ResetAuthenticator.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/ResetAuthenticator.razor @@ -5,7 +5,6 @@ @inject UserManager UserManager @inject SignInManager SignInManager -@inject IdentityUserAccessor UserAccessor @inject IdentityRedirectManager RedirectManager @inject ILogger Logger @@ -36,7 +35,13 @@ private async Task OnSubmitAsync() { - var user = await UserAccessor.GetRequiredUserAsync(HttpContext); + var user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + await UserManager.SetTwoFactorEnabledAsync(user, false); await UserManager.ResetAuthenticatorKeyAsync(user); var userId = await UserManager.GetUserIdAsync(user); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/SetPassword.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/SetPassword.razor index 79eabe780fff..c9c7b26317cf 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/SetPassword.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/SetPassword.razor @@ -6,7 +6,6 @@ @inject UserManager UserManager @inject SignInManager SignInManager -@inject IdentityUserAccessor UserAccessor @inject IdentityRedirectManager RedirectManager Set password @@ -39,7 +38,7 @@ @code { private string? message; - private ApplicationUser user = default!; + private ApplicationUser? user; [CascadingParameter] private HttpContext HttpContext { get; set; } = default!; @@ -49,7 +48,12 @@ protected override async Task OnInitializedAsync() { - user = await UserAccessor.GetRequiredUserAsync(HttpContext); + user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } var hasPassword = await UserManager.HasPasswordAsync(user); if (hasPassword) @@ -60,6 +64,12 @@ private async Task OnValidSubmitAsync() { + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + var addPasswordResult = await UserManager.AddPasswordAsync(user, Input.NewPassword!); if (!addPasswordResult.Succeeded) { diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/TwoFactorAuthentication.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/TwoFactorAuthentication.razor index d15097a9ed16..08fae2319374 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/TwoFactorAuthentication.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/Manage/TwoFactorAuthentication.razor @@ -6,7 +6,6 @@ @inject UserManager UserManager @inject SignInManager SignInManager -@inject IdentityUserAccessor UserAccessor @inject IdentityRedirectManager RedirectManager Two-factor authentication (2FA) @@ -82,7 +81,13 @@ else protected override async Task OnInitializedAsync() { - var user = await UserAccessor.GetRequiredUserAsync(HttpContext); + var user = await UserManager.GetUserAsync(HttpContext.User); + if (user is null) + { + RedirectManager.RedirectToInvalidUser(UserManager, HttpContext); + return; + } + canTrack = HttpContext.Features.Get()?.CanTrack ?? true; hasAuthenticator = await UserManager.GetAuthenticatorKeyAsync(user) is not null; is2faEnabled = await UserManager.GetTwoFactorEnabledAsync(user); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/RegisterConfirmation.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/RegisterConfirmation.razor index ec74ea584ef8..52ee9594920b 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/RegisterConfirmation.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/RegisterConfirmation.razor @@ -46,6 +46,7 @@ else if (Email is null) { RedirectManager.RedirectTo(""); + return; } var user = await UserManager.FindByEmailAsync(Email); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ResetPassword.razor b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ResetPassword.razor index 61e07c0b8de0..4c88c56665ae 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ResetPassword.razor +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Account/Pages/ResetPassword.razor @@ -58,6 +58,7 @@ if (Code is null) { RedirectManager.RedirectTo("Account/InvalidPasswordReset"); + return; } Input.Code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code)); @@ -70,6 +71,7 @@ { // Don't reveal that the user does not exist RedirectManager.RedirectTo("Account/ResetPasswordConfirmation"); + return; } var result = await UserManager.ResetPasswordAsync(user, Input.Code, Input.Password); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Program.Main.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Program.Main.cs index 6a2069105227..d37d24553867 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Program.Main.cs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Program.Main.cs @@ -46,7 +46,6 @@ public static void Main(string[] args) #if (IndividualLocalAuth) builder.Services.AddCascadingAuthenticationState(); - builder.Services.AddScoped(); builder.Services.AddScoped(); #if (UseServer) builder.Services.AddScoped(); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Program.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Program.cs index b0186c948ca4..7ea8e5a50033 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Program.cs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Program.cs @@ -40,7 +40,6 @@ #if (IndividualLocalAuth) builder.Services.AddCascadingAuthenticationState(); -builder.Services.AddScoped(); builder.Services.AddScoped(); #if (UseServer) builder.Services.AddScoped(); diff --git a/src/ProjectTemplates/test/Templates.Tests/template-baselines.json b/src/ProjectTemplates/test/Templates.Tests/template-baselines.json index 5142ac24928e..d8d269531f22 100644 --- a/src/ProjectTemplates/test/Templates.Tests/template-baselines.json +++ b/src/ProjectTemplates/test/Templates.Tests/template-baselines.json @@ -600,7 +600,6 @@ "Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs", "Components/Account/IdentityNoOpEmailSender.cs", "Components/Account/IdentityRedirectManager.cs", - "Components/Account/IdentityUserAccessor.cs", "Components/Account/Pages/AccessDenied.razor", "Components/Account/Pages/ConfirmEmail.razor", "Components/Account/Pages/ConfirmEmailChange.razor", @@ -791,7 +790,6 @@ "Components/Account/IdentityNoOpEmailSender.cs", "Components/Account/IdentityRedirectManager.cs", "Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs", - "Components/Account/IdentityUserAccessor.cs", "Components/Account/Pages/AccessDenied.razor", "Components/Account/Pages/ConfirmEmail.razor", "Components/Account/Pages/ConfirmEmailChange.razor", @@ -913,7 +911,6 @@ "Components/Account/IdentityNoOpEmailSender.cs", "Components/Account/IdentityRedirectManager.cs", "Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs", - "Components/Account/IdentityUserAccessor.cs", "Components/Account/Pages/AccessDenied.razor", "Components/Account/Pages/ConfirmEmail.razor", "Components/Account/Pages/ConfirmEmailChange.razor", @@ -1118,7 +1115,6 @@ "{ProjectName}/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs", "{ProjectName}/Components/Account/IdentityNoOpEmailSender.cs", "{ProjectName}/Components/Account/IdentityRedirectManager.cs", - "{ProjectName}/Components/Account/IdentityUserAccessor.cs", "{ProjectName}/Components/Account/Pages/AccessDenied.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmail.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmailChange.razor", @@ -1322,7 +1318,6 @@ "{ProjectName}/Components/Account/IdentityNoOpEmailSender.cs", "{ProjectName}/Components/Account/IdentityRedirectManager.cs", "{ProjectName}/Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs", - "{ProjectName}/Components/Account/IdentityUserAccessor.cs", "{ProjectName}/Components/Account/Pages/AccessDenied.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmail.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmailChange.razor", @@ -1772,7 +1767,6 @@ "{ProjectName}/Components/Account/IdentityNoOpEmailSender.cs", "{ProjectName}/Components/Account/IdentityRedirectManager.cs", "{ProjectName}/Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs", - "{ProjectName}/Components/Account/IdentityUserAccessor.cs", "{ProjectName}/Components/Account/Pages/AccessDenied.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmail.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmailChange.razor", @@ -1843,7 +1837,6 @@ "Components/Account/IdentityNoOpEmailSender.cs", "Components/Account/IdentityRedirectManager.cs", "Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs", - "Components/Account/IdentityUserAccessor.cs", "Components/Account/Pages/AccessDenied.razor", "Components/Account/Pages/ConfirmEmail.razor", "Components/Account/Pages/ConfirmEmailChange.razor", @@ -1981,7 +1974,6 @@ "{ProjectName}/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs", "{ProjectName}/Components/Account/IdentityNoOpEmailSender.cs", "{ProjectName}/Components/Account/IdentityRedirectManager.cs", - "{ProjectName}/Components/Account/IdentityUserAccessor.cs", "{ProjectName}/Components/Account/Pages/AccessDenied.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmail.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmailChange.razor", @@ -2110,7 +2102,6 @@ "{ProjectName}/Components/Account/IdentityNoOpEmailSender.cs", "{ProjectName}/Components/Account/IdentityRedirectManager.cs", "{ProjectName}/Components/Account/IdentityRevalidatingAuthenticationStateProvider.cs", - "{ProjectName}/Components/Account/IdentityUserAccessor.cs", "{ProjectName}/Components/Account/Pages/AccessDenied.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmail.razor", "{ProjectName}/Components/Account/Pages/ConfirmEmailChange.razor",