未注册身份验证 AuthenticationStateProvider 的 Blazor Wasm 托管预渲染

Posted

技术标签:

【中文标题】未注册身份验证 AuthenticationStateProvider 的 Blazor Wasm 托管预渲染【英文标题】:Blazor Wasm Hosted Prerender with Authentication AuthenticationStateProvider not registered 【发布时间】:2021-03-02 03:09:11 【问题描述】:

我有一个使用 Blazor WebAssembly Hosted with Authentication 的开箱即用的 VS 模板,并将其转换为使用 PreRendering。但是,这样做看起来有很多服务包含在客户端中,而在服务器端没有提供。这是一个例外

处理请求时发生未处理的异常。 InvalidOperationException:无法为属性提供值 'AuthenticationStateProvider' 类型 'Microsoft.AspNetCore.Components.Authorization.CascadingAuthenticationState'。 没有注册类型的服务 'Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider'。 Microsoft.AspNetCore.Components.ComponentFactory+c__DisplayClass6_0.g__Initialize|2(IServiceProvider serviceProvider,IComponent 组件)

堆栈查询 Cookie 标头路由 InvalidOperationException:不能 为类型上的属性“AuthenticationStateProvider”提供一个值 'Microsoft.AspNetCore.Components.Authorization.CascadingAuthenticationState'。 没有注册类型的服务 'Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider'。 Microsoft.AspNetCore.Components.ComponentFactory+c__DisplayClass6_0.g__Initialize|2(IServiceProvider serviceProvider,IComponent 组件) Microsoft.AspNetCore.Components.ComponentFactory.PerformPropertyInjection(IServiceProvider serviceProvider,IComponent 实例) Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider 服务提供者,类型组件类型) Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(参考 RenderTreeFrame 框架,int parentComponentId) Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(参考 DiffContext diffContext, int frameIndex) Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(参考 DiffContext diffContext, int frameIndex) Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(参考 DiffContext diffContext, int newFrameIndex) Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(参考 DiffContext diffContext, int oldStartIndex, int oldEndIndexExcl, int newStartIndex, int newEndIndexExcl) Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(渲染器 renderer, RenderBatchBuilder batchBuilder, int componentId, ArrayRange oldTree, ArrayRange 新树) Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment (renderFragment) Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry 渲染队列条目) Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue() Microsoft.AspNetCore.Components.Rendering.htmlRenderer.HandleException(异常 例外) Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue() Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessPendingRender() Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(int componentId, RenderFragment (renderFragment) Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged() Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync() Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync() Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.HandleException(异常 例外) Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToPendingTasks(任务 任务) Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView 参数) Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderRootComponentAsync(int componentId, ParameterView 初始参数) Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.CreateInitialRenderAsync(类型 componentType, ParameterView 初始参数) Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.RenderComponentAsync(类型 componentType, ParameterView 初始参数) Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext+c__11+d.MoveNext() Microsoft.AspNetCore.Mvc.ViewFeatures.StaticComponentRenderer.PrerenderComponentAsync(ParameterView 参数,HttpContext httpContext,类型组件类型) Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.PrerenderedWebAssemblyComponentAsync(HttpContext 上下文、类型类型、ParameterView parametersCollection) Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.RenderComponentAsync(ViewContext viewContext, 类型 componentType, RenderMode renderMode, object 参数) Microsoft.AspNetCore.Mvc.TagHelpers.ComponentTagHelper.ProcessAsync(TagHelperContext 上下文,TagHelperOutput 输出) Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.g__Awaited|0_0(任务 任务, TagHelperExecutionContext executionContext, int i, int count) BBQFriend.Server.Pages.Pages__Host.b__9_1() 在 _Host.cshtml + Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync() BBQFriend.Server.Pages.Pages__Host.ExecuteAsync() Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage 页面,ViewContext 上下文) Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage 页面,ViewContext 上下文,bool invokeViewStarts) Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext 语境) Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, 字符串 contentType, Nullable statusCode) Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, 字符串 contentType, Nullable statusCode) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0(ResourceInvoker 调用者,Task lastTask,State next, 范围作用域,对象状态,bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed 语境) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext(ref State next, ref Scope scope, ref object state, ref 布尔已完成) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters() Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker 调用者,任务 lastTask,下一个状态,作用域范围,对象状态,布尔 完成了) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed 语境) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(参考状态 接下来,ref Scope 范围,ref 对象状态,ref bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker 调用者、任务任务、IDisposable 范围) Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(端点 端点、任务 requestTask、ILogger 记录器) Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext 语境) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext 语境) IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext 上下文、IEndpointRouter 路由器、IUserSession 会话、IEventService 事件,IBackChannelLogoutService backChannelLogoutService) IdentityServer4.Hosting.MutualTlsEndpointMiddleware.Invoke(HttpContext 上下文,IAuthenticationSchemeProvider 方案) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext 上下文)IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext 语境) Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext 语境) Microsoft.AspNetCore.Builder.Extensions.MapMiddleware.Invoke(HttpContext 语境) Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext 语境) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext 上下文)

我可以在Server startup.cs中注册哪些服务来注册必要的服务?

【问题讨论】:

【参考方案1】:

我也遇到过同样的问题,我在TheIdServer 通过注册和存根一些服务解决了这个问题:

services.AddRemoteAuthentication<RemoteAuthenticationState, RemoteUserAccount, OidcProviderOptions>();
services.AddScoped<AuthenticationStateProvider, RemoteAuthenticationService>()
    .AddScoped<SignOutSessionStateManager>()
    .AddTransient<IAccessTokenProvider, AccessTokenProvider>()
    .AddTransient<Microsoft.JSInterop.IJSRuntime, JSRuntime>();

RemoteAuthenticationService.cs

using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using System.Threading.Tasks;

namespace Aguacongas.TheIdServer.Services

    public class RemoteAuthenticationService : ServerAuthenticationStateProvider, IRemoteAuthenticationService<RemoteAuthenticationState>
    

        public Task<RemoteAuthenticationResult<RemoteAuthenticationState>> CompleteSignInAsync(RemoteAuthenticationContext<RemoteAuthenticationState> context)
        
            return Success(context);
        

        public Task<RemoteAuthenticationResult<RemoteAuthenticationState>> CompleteSignOutAsync(RemoteAuthenticationContext<RemoteAuthenticationState> context)
        
            return Success(context);
        

        public Task<RemoteAuthenticationResult<RemoteAuthenticationState>> SignInAsync(RemoteAuthenticationContext<RemoteAuthenticationState> context)
        
            return Success(context);
        

        public Task<RemoteAuthenticationResult<RemoteAuthenticationState>> SignOutAsync(RemoteAuthenticationContext<RemoteAuthenticationState> context)
        
            return Success(context);
        

        private static Task<RemoteAuthenticationResult<RemoteAuthenticationState>> Success(RemoteAuthenticationContext<RemoteAuthenticationState> context)
        
            return Task.FromResult(new RemoteAuthenticationResult<RemoteAuthenticationState>
            
                State = context.State,
                Status = RemoteAuthenticationStatus.Success
            );
        
    

AccessTokenProvider.cs

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using System;
using System.Threading.Tasks;

namespace Aguacongas.TheIdServer.Services

    public class AccessTokenProvider : IAccessTokenProvider
    
        public ValueTask<AccessTokenResult> RequestAccessToken()
        
            throw new NotImplementedException();
        

        public ValueTask<AccessTokenResult> RequestAccessToken(AccessTokenRequestOptions options)
        
            throw new NotImplementedException();
        
    

JSRuntime.cs

using Microsoft.JSInterop;
using System.Threading;
using System.Threading.Tasks;

namespace Aguacongas.TheIdServer.Services

    public class JSRuntime : IJSRuntime
    
        public ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args)
        
            return new ValueTask<TValue>();
        

        public ValueTask<TValue> InvokeAsync<TValue>(string identifier, CancellationToken cancellationToken, object[] args)
        
            return new ValueTask<TValue>();
        
    

我也删除了:

builder.RootComponents.Add<App>("app");

来自 blazor 应用的 Program.cs

【讨论】:

非常感谢您帮助我前进!【参考方案2】:

所以答案是将services.AddApiAuthorization();添加到服务器Startup.cs

这解决了缺少服务注册的问题,但是之后还有一个错误。从目前的情况来看,身份验证不支持预渲染。

处理请求时发生未处理的异常。 InvalidOperationException:在服务器端预呈现期间无法发出 javascript 互操作调用,因为该页面尚未加载到浏览器中。预渲染组件必须将任何 JavaScript 互操作调用包装在条件逻辑中,以确保在预渲染期间不会尝试这些互操作调用。 Microsoft.AspNetCore.Mvc.ViewFeatures.UnsupportedJavaScriptRuntime.Microsoft.JSInterop.IJSRuntime.InvokeAsync(string identifier, object[] args)

【讨论】:

以上是关于未注册身份验证 AuthenticationStateProvider 的 Blazor Wasm 托管预渲染的主要内容,如果未能解决你的问题,请参考以下文章

<FIRMessaging/WARNING> FIRMessaging 注册未准备好使用身份验证凭据

颤动的firebase身份验证提供者未通知

更新身份验证状态时未调用 Bloc 侦听器?

GUNjs 用户未在隐身窗口中获得身份验证

密码注册后 Firebase 云功能出现未经身份验证的错误

Firebase 身份验证会话未过期 [重复]