Blazor WASM排除Razor页面与Controller认证仍报错,求解决
Blazor WASM匿名页面访问抛出AccessTokenNotAvailableException的解决办法
问题情况
我创建了带有Identity独立账户的Blazor WebAssembly项目,复制FetchData.razor生成FetchPeople.razor页面,希望允许该页面匿名访问。已在Razor页面和对应的PeopleController上添加[AllowAnonymous]特性,但访问页面时控制台抛出Microsoft.AspNetCore.Components.WebAssembly.Authentication.AccessTokenNotAvailableException异常。
Razor页面代码
@page "/fetchpeople" @using Booking.Shared @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.WebAssembly.Authentication @inject HttpClient Http @attribute [AllowAnonymous] <PageTitle>People</PageTitle> <h1>People</h1> <p>This component demonstrates fetching data from the server.</p> @if (forecasts == null) { <p><em>Loading...</em></p> } else { <table class="table"> <thead> <tr> <th>Date</th> <th>Temp. (C)</th> <th>Temp. (F)</th> <th>Summary</th> </tr> </thead> <tbody> @foreach (var forecast in forecasts) { <tr> <td>@forecast.Id</td> <td>@forecast.FirstName</td> <td>@forecast.LastName</td> <td>@forecast.LastName</td> </tr> } </tbody> </table> } @code { private PersonModel[]? forecasts; protected override async Task OnInitializedAsync() { forecasts = await Http.GetFromJsonAsync<PersonModel[]>("People"); } }
Controller代码
using Booking.Shared; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using System.Xml.Linq; using System.Collections.Generic; using Booking.Server.Data; using Microsoft.AspNetCore.Authorization; namespace a1.Server.Controllers { [AllowAnonymous] [ApiController] [Route("[controller]")] public class PeopleController : ControllerBase { private readonly ILogger<PeopleController> _logger; private readonly IDataAccess data; public PeopleController(ILogger<PeopleController> logger, IDataAccess data) { _logger = logger; this.data = data; } [HttpGet] public IEnumerable<PersonModel> Get() { return data.testSql().Result.ToArray(); } } }
控制台错误信息
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: '' Microsoft.AspNetCore.Components.WebAssembly.Authentication.AccessTokenNotAvailableException: '' at Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__13`1[[Booking.Shared.PersonModel[], Booking.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext() at Booking.Client.Pages.FetchPeople.OnInitializedAsync() in E:\2022_hoplun_dotnet\login1\Booking\Booking\Client\Pages\FetchPeople.razor:line 49 at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync() at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState) window.Module.s.printErr @ blazor.webassembly.js:1 Fe._internal.dotNetCriticalError @ blazor.webassembly.js:1 St @ blazor.webassembly.js:1 _mono_wasm_invoke_js_blazor @ dotnet.6.0.11.yp634snq4a.js:1 $func219 @ 00971d3e:0x1a492 $func167 @ 00971d3e:0xce60 $func166 @ 00971d3e:0xbd73 $func2815 @ 00971d3e:0xabec4 $func1619 @ 00971d3e:0x6fc85 $func1623 @ 00971d3e:0x702f2 $mono_wasm_invoke_method @ 00971d3e:0x969f Module._mono_wasm_invoke_method @ dotnet.6.0.11.yp634snq4a.js:1 managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS @ managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS:16 endInvokeJSFromDotNet @ blazor.webassembly.js:1 (anonymous) @ blazor.webassembly.js:1 Promise.then (async) beginInvokeJSFromDotNet @ blazor.webassembly.js:1 St @ blazor.webassembly.js:1 _mono_wasm_invoke_js_blazor @ dotnet.6.0.11.yp634snq4a.js:1 $func219 @ 00971d3e:0x1a492 $func167 @ 00971d3e:0xce60 $func166 @ 00971d3e:0xbd73 $func2815 @ 00971d3e:0xabec4 $func1619 @ 00971d3e:0x6fc85 $func1623 @ 00971d3e:0x702f2 $mono_wasm_invoke_method @ 00971d3e:0x969f Module._mono_wasm_invoke_method @ dotnet.6.0.11.yp634snq4a.js:1 managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS @ managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS:16 endInvokeJSFromDotNet @ blazor.webassembly.js:1 (anonymous) @ blazor.webassembly.js:1 Promise.then (async) beginInvokeJSFromDotNet @ blazor.webassembly.js:1 St @ blazor.webassembly.js:1 _mono_wasm_invoke_js_blazor @ dotnet.6.0.11.yp634snq4a.js:1 $func219 @ 00971d3e:0x1a492 $func167 @ 00971d3e:0xce60 $func166 @ 00971d3e:0xbd73 $func2815 @ 00971d3e:0xabec4 $func1619 @ 00971d3e:0x6fc85 $func1623 @ 00971d3e:0x702f2 $mono_wasm_invoke_method @ 00971d3e:0x969f Module._mono_wasm_invoke_method @ dotnet.6.0.11.yp634snq4a.js:1 managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS @ managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS:16 endInvokeJSFromDotNet @ blazor.webassembly.js:1 (anonymous) @ blazor.webassembly.js:1 Promise.then (async) beginInvokeJSFromDotNet @ blazor.webassembly.js:1 St @ blazor.webassembly.js:1 _mono_wasm_invoke_js_blazor @ dotnet.6.0.11.yp634snq4a.js:1 $func219 @ 00971d3e:0x1a492 $func167 @ 00971d3e:0xce60 $func166 @ 00971d3e:0xbd73 $func2815 @ 00971d3e:0xabec4 $func1619 @ 00971d3e:0x6fc85 $func1623 @ 00971d3e:0x702f2 $mono_wasm_invoke_method @ 00971d3e:0x969f Module._mono_wasm_invoke_method @ dotnet.6.0.11.yp634snq4a.js:1 managed_BINDINGS_SetTaskSourceResult @ managed_BINDINGS_SetTaskSourceResult:17 (anonymous) @ dotnet.6.0.11.yp634snq4a.js:1 Promise.then (async) _wrap_js_thenable_as_task @ dotnet.6.0.11.yp634snq4a.js:1 _js_to_mono_obj @ dotnet.6.0.11.yp634snq4a.js:1 js_to_mono_obj @ dotnet.6.0.11.yp634snq4a.js:1 receiveHotReload @ blazor-hotreload.js:2 St @ blazor.webassembly.js:1 _mono_wasm_invoke_js_blazor @ dotnet.6.0.11.yp634snq4a.js:1 $func219 @ 00971d3e:0x1a492 $func167 @ 00971d3e:0xce60 $func166 @ 00971d3e:0xbd73 $func2815 @ 00971d3e:0xabec4 $func1619 @ 00971d3e:0x6fc85 $func1623 @ 00971d3e:0x702f2 $mono_wasm_invoke_method @ 00971d3e:0x969f Module._mono_wasm_invoke_method @ dotnet.6.0.11.yp634snq4a.js:1 managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS @ managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_EndInvokeJS:16 endInvokeJSFromDotNet @ blazor.webassembly.js:1 (anonymous) @ blazor.webassembly.js:1 Promise.then (async) beginInvokeJSFromDotNet @ blazor.webassembly.js:1 St @ blazor.webassembly.js:1 _mono_wasm_invoke_js_blazor @ dotnet.6.0.11.yp634snq4a.js:1 $func219 @ 00971d3e:0x1a492 $func167 @ 00971d3e:0xce60 $func166 @ 00971d3e:0xbd73 $func2815 @ 00971d3e:0xabec4 $func1619 @ 00971d3e:0x6fc85 $func1623 @ 00971d3e:0x702f2 $mono_wasm_invoke_method @ 00971d3e:0x969f Module._mono_wasm_invoke_method @ dotnet.6.0.11.yp634snq4a.js:1 managed_BINDINGS_SetTaskSourceResult @ managed_BINDINGS_SetTaskSourceResult:17 (anonymous) @ dotnet.6.0.11.yp634snq4a.js:1 Promise.then (async) _wrap_js_thenable_as_task @ dotnet.6.0.11.yp634snq4a.js:1 _js_to_mono_obj @ dotnet.6.0.11.yp634snq4a.js:1 js_to_mono_obj @ dotnet.6.0.11.yp634snq4a.js:1 Fe._internal.getSatelliteAssemblies @ blazor.webassembly.js:1 St @ blazor.webassembly.js:1 _mono_wasm_invoke_js_blazor @ dotnet.6.0.11.yp634snq4a.js:1 $func219 @ 00971d3e:0x1a492 $func167 @ 00971d3e:0xce60 $func166 @ 00971d3e:0xbd73 $func2815 @ 00971d3e:0xabec4 $func1619 @ 00971d3e:0x6fc85 $func1623 @ 00971d3e:0x702f2 $mono_wasm_invoke_method @ 00971d3e:0x969f Module._mono_wasm_invoke_method @ dotnet.6.0.11.yp634snq4a.js:1 _call_method_with_converted_args @ dotnet.6.0.11.yp634snq4a.js:1 call_method @ dotnet.6.0.11.yp634snq4a.js:1 (anonymous) @ dotnet.6.0.11.yp634snq4a.js:1 call_assembly_entry_point @ dotnet.6.0.11.yp634snq4a.js:1 callEntryPoint @ blazor.webassembly.js:1 At @ blazor.webassembly.js:1 await in At (async) (anonymous) @ blazor.webassembly.js:1 (anonymous) @ blazor.webassembly.js:1
问题原因
你注入的默认HttpClient被项目配置了AuthorizationMessageHandler,这个处理器会自动尝试为所有请求附加用户的访问令牌。当匿名访问时,没有可用的令牌,就会触发AccessTokenNotAvailableException。
解决办法
创建一个专门用于匿名请求的HttpClient实例,跳过授权令牌的自动附加:
- 在客户端项目的
Program.cs中注册命名HttpClient:
builder.Services.AddHttpClient("AnonymousClient", client => { client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress); });
- 修改FetchPeople.razor,注入
IHttpClientFactory替代默认的HttpClient:
@inject IHttpClientFactory HttpClientFactory
- 在
OnInitializedAsync方法中使用命名客户端发起请求:
protected override async Task OnInitializedAsync() { var httpClient = HttpClientFactory.CreateClient("AnonymousClient"); forecasts = await httpClient.GetFromJsonAsync<PersonModel[]>("People"); }
这样就能让匿名页面正常访问无需令牌的接口了。
内容的提问来源于stack exchange,提问作者hkguile
相关产品推荐
相关产品推荐

