Blazor服务器无法访问具有[授权]属性的控制器



我对网站很陌生,所以这可能有点天真。从基本的Blazor服务器(blazorserver(模板和用于身份验证的单个用户帐户开始,我通过转到项目添加控制器并选择具有读/写操作的API控制器,将DefaultController添加到我的Blazor应用程序中。

然后我添加了NuGet包Microsoft.AspNetCore.Blazor.HttpClient并添加到Startup.cs:

services.AddScoped<HttpClient>();

我还将HttpClientNavigationManager注入到FetchData.razor页面中。然后,我在FetchData.razor页面上添加了一个按钮和功能:

<button @onclick="@TryIt">Try It</button>
private async Task TryIt()
{
var x = await httpClient.GetJsonAsync<List<string>>($"{navigationManager.BaseUri}api/Default");
}

我运行该网站并单击尝试按钮,它运行良好:我看到了列表中的两项。太棒了

然后,我将[Authorize]属性添加到控制器中的HttpGet()操作中:

// GET: api/Default
[HttpGet]
[Authorize]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}

当我再次运行该网站并单击尝试时,没有任何乐趣(未处理的异常(。好吧,也许我需要登录?运行网站,登录(在创建数据库并注册用户之后(,然后单击尝试。再次,我在控制台中得到了一个可怕的异常:

Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer: Warning: Unhandled exception rendering component: '<' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
System.Text.Json.JsonException: '<' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
---> System.Text.Json.JsonReaderException: '<' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first)
at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
at System.Text.Json.Utf8JsonReader.Read()
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, JsonReaderException ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(Type returnType, JsonSerializerOptions options, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.Deserialize(String json, Type returnType, JsonSerializerOptions options)
at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
at Microsoft.AspNetCore.Components.HttpClientJsonExtensions.GetJsonAsync[T](HttpClient httpClient, String requestUri)
at BlazorApp.Pages.FetchData.TryIt() in E:DLSSandbox7BlazorAppSolutionBlazorAppPagesFetchData.razor:line 57
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost: Error: Unhandled exception in circuit 'H-xRrymKJQEov3vkCpOcExCeuUA2S2b1e15y6QSjxvw'.

我一直在读到,要做到这一点,我可能需要向HTTP请求添加一个令牌,但我不知道如何获得令牌。我走对了吗?我需要添加什么?我错过了什么?

由于我对这方面还很陌生,我可以尽可能多地提供指导,尽可能多的提供细节。

首先,由于JsonSerializer无法反序列化传递给它的内容,因此引发了异常。它希望获得可以反序列化到List的JSON,但从服务器收到一条消息,报告发生了错误。此消息以HTML的形式提供。

您不应该在Blazor服务器应用程序中使用Microsoft.AspNetCore.Blazor.HttpClient。它旨在用于Blazor WebAssembly应用程序。使用IHttpClientFactory在服务器端Blazor中使用HttpClient服务。

使用带有单个用户帐户的模板进行身份验证意味着您的用户将通过Asp.Net核心身份系统(IdentityUI(进行身份验证,该系统包括数据库、模型等。但这只与身份验证有关。

现在,如果你想访问WebApi端点,并想通过使用Authorize属性来保护这些端点,你需要使用授权系统,如OpenIDConnect等。

首先,我建议您使用JWT令牌身份验证向经过身份验证的用户颁发JWT令牌。您可以专用一个控制器来验证用户,创建一个JWT令牌,其中包含有关用户的各种声明。在用户经过身份验证后,此JWT令牌只创建一次,并将其传递给调用代码(Blazor服务器应用程序(,该代码应将其存储在本地存储(JavaScript本地存储(中。现在,每当您想从安全的WebApi端点检索给定用户的数据时,都应该从本地存储读取Jwt令牌,并将其添加到HTTP请求的授权标头。以下是如何在Authorization标头中发出传递Jwt令牌的HTTP请求的演示。注意:这是使用您添加的包完成的,不建议将其与服务器端Blazor一起使用。您可以暂时使用它,但在一天结束时,您应该转到IHttpClientFactory。

@code {
User[] users;
protected override async Task OnInitializedAsync()
{
var token = await TokenProvider.GetTokenAsync();
users = await Http.GetJsonAsync<User[]>(
"api/users",
new AuthenticationHeaderValue("Bearer", token));
}

}

注意:这个主题非常全面,我建议你使用文档来了解它的基本内容。我和其他人也有关于身份验证和授权的答案,你可以从中学到很多。学习使用Blazor中与授权相关的组件和对象也是至关重要的。

希望这能帮助。。。

最新更新