Blazor 添加 HttpClientHandler 以在请求时将 Jwt 添加到 HTTP 标头

Mat*_*ynn 5 c# asp.net-core blazor blazor-client-side

我将Visual Studio 2019.Net Core 3.0.0-preview-7与标准 Blazor 客户端、服务器和共享模板一起使用。

在应用程序中,我们的服务器端 WebApi 应用程序将始终需要一个 JWT 令牌出现在标头中以进行授权。

从以下来看

在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求

我创建了以下处理程序;

public class JwtTokenHeaderHandler : DelegatingHandler
{
    private readonly ILocalStorageService _localStorage;

    public JwtTokenHeaderHandler(ILocalStorageService localStorage)
    {
        _localStorage = localStorage;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (!request.Headers.Contains("bearer"))
        {
            var savedToken = await _localStorage.GetItemAsync<string>("authToken");

            if (!string.IsNullOrWhiteSpace(savedToken))
            {
                request.Headers.Add("bearer", savedToken);
            }
        }

        return await base.SendAsync(request, cancellationToken);
    }
}
Run Code Online (Sandbox Code Playgroud)

我用来Blazored.LocalStorage从 localstorage 获取保存的令牌并将其添加到标题的地方。

现在,在这一点上我不知道该怎么做,好像我将以下内容添加到Blazor.Client Startup.cs;

services.AddTransient<JwtTokenHeaderHandler>();
services.AddHttpClient("JwtTokenHandler")
    .AddHttpMessageHandler<JwtTokenHeaderHandler>();
Run Code Online (Sandbox Code Playgroud)

我收到错误信息;

“IServiceCollection”不包含“AddHttpClient”的定义,并且找不到接受“IServiceCollection”类型的第一个参数的可访问扩展方法“AddHttpClient”(您是否缺少 using 指令或程序集引用?)

任何人都可以指导我在这里做错什么吗?

小智 5

我找到了一个非常好的教程和示例来演示这一点(包含基于角色/策略的声明): https ://chrissainty.com/securing-your-blazor-apps-authentication-with-clientside-blazor-using-webapi-aspnet-核心身份/

下面是一个摘录,在默认 http 客户端上设置默认请求标头(通过 DI)。然后,对您的 Web api 的所有调用都将包含不记名令牌:

public class ApiAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly HttpClient _httpClient;
    private readonly ILocalStorageService _localStorage;

    public ApiAuthenticationStateProvider(HttpClient httpClient, ILocalStorageService localStorage)
    {
        _httpClient = httpClient;
        _localStorage = localStorage;
    }
    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var savedToken = await _localStorage.GetItemAsync<string>("authToken");

        if (string.IsNullOrWhiteSpace(savedToken))
        {
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
        }

        // **************    Set JWT header       ****************
        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", savedToken);
        // *******************************************************

        return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(savedToken), "jwt")));
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)


Isa*_*aac 4

@Matthew Flynn,目前您无法在客户端 Blazor 上使用 IHttpClientFactory。

而且您不必从 HttpMessageHandler (DelegatingHandler) 派生。Blazor 已经做到了。以下是扩展 HttpClient 服务功能的扩展类,以启用将 Jwt 令牌添加到请求消息标头的功能...

服务扩展.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Security.Claims;
    using System.Text;
    using System.Text.Json.Serialization;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Components;
    using Microsoft.Extensions.DependencyInjection;

 public static class ServiceExtensions
    {    
     public static async Task<T> GetJsonAsync<T>(this HttpClient httpClient, string url, AuthenticationHeaderValue authorization)
            {
                var request = new HttpRequestMessage(HttpMethod.Get, url);
                request.Headers.Authorization = authorization;

                var response = await httpClient.SendAsync(request);
                var responseBytes = await response.Content.ReadAsByteArrayAsync();
                return JsonSerializer.Parse<T>(responseBytes, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
            }
}
Run Code Online (Sandbox Code Playgroud)

下面展示了如何调用 Web Api 上的端点,传递从 localStorage 读取的 Jwt 令牌。(顺便说一句,这些版本都没有数据保护)

索引剃刀

@page "/"

@inject ILocalStorageService localStorage
@inject HttpClient Http

<div class="mdc-card main-content-card">
    <h1 class="@MdcTypography.H4">Hello, world!</h1>

    Welcome to your new app.
</div>

// Razor content to display emloyees come here.....

@code {
Employee[] employees;

    protected override async Task OnInitAsync()
    {
        var token = await localStorage.GetTokenAsync();
        employees = await Http.GetJsonAsync<Employee[]>(
            "api/employees",
            new AuthenticationHeaderValue("Bearer", token));
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这有效...如果没有,并且您无法解决错误,请来这里告诉社区...