在 blazor 中使用 WebAPI 进行身份验证

A.A*_*A.A 5 c# blazor blazor-server-side

在创建 ASP.NET WebAPI 项目时,我正在使用 VS 2019 为天气预报数据提供的基本模板,并添加了一些非常基本的用户登录身份验证和对 JWT 令牌的支持,一切正常。

我正在尝试创建一个 blazor 客户端项目来使用 API 并在页面上显示数据。AFAIK Blazor 不支持 localstorage 所以我使用 Blazored LocalStorage 包给我这个能力。我的问题源于事实上在服务器端 blazor ( https://github.com/aspnet/AspNetCore/issues/13396 ) 中通过 OnInitializedAsync() 使用 JS 是不可能的,因此我不确定一个人应该如何消费这些 web api 调用。因为这会产生空引用异常

protected override async Task OnInitializedAsync()
{
    var client = HttpFactory.CreateClient();
    var token = await LocalStorage.GetItemAsync<string>("authToken");
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var response = await client.GetAsync("url/WeatherForecast");
    var str = await response.Content.ReadAsStringAsync();
    Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);
}
Run Code Online (Sandbox Code Playgroud)

一个建议是使用 OnAfterRenderAsync() 方法来调用它们,因为届时 JS 将准备就绪。哪个半有效,但显然 UI 不匹配,因为它需要刷新 - 但是手动刷新似乎我必须调用 StateHasChanged(); 这又再次调用 OnAfterRender 方法,因此我不得不进行检查,但这最终感觉非常糟糕。

private bool hasRendered;
protected override async Task OnAfterRenderAsync(bool _)
{
    if (!hasRendered) return;
    var client = HttpFactory.CreateClient();
    var token = await LocalStorage.GetItemAsync<string>("authToken");
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var response = await client.GetAsync("https://url/WeatherForecast");
    var str = await response.Content.ReadAsStringAsync();
    Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);

    StateHasChanged();

    hasRendered = true;
}
Run Code Online (Sandbox Code Playgroud)

使用带有身份验证的 API 并在客户端正确显示数据的正确方法是什么?

附带问题 HttpClient 似乎不能在服务器端注入,建议使用 HttpClientFactory - 在每个请求上创建一个客户端还是创建一个单例并在整个客户端项目中重复使用是个好主意吗?

dan*_*era 1

Q1

一种建议是使用 OnAfterRenderAsync() 方法来调用它们,因为那时 JS 就已经准备好了。哪个半有效,但显然 UI 不匹配,因为它需要刷新 - 但是要手动刷新,我似乎必须调用 StateHasChanged(); 这又会再次调用 OnAfterRender 方法,因此我必须进行检查,但这最终感觉非常糟糕。

所有遇到同样问题的人,因为在Lifecyclemethods中记录了new OnAfterRenderAsyncwith parm :firstRender

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await ... /// your auth code here.
    }
}
Run Code Online (Sandbox Code Playgroud)

Q2

附带问题 HttpClient 似乎无法在服务器端注入,建议使用 HttpClientFactory - 在每个请求上创建一个客户端或创建一个单例并在整个客户端项目中重复使用是一个好主意吗?

简化:我建议您为后端调用创建两个外部库:一个使用 http 请求(对于 blazor wasm 托管模型),另一个仅调用 c# 后端函数(对于 blazor 服务器)。两者都具有用于后端调用的通用接口。使用DI 为每个托管模型设置正确的库