Blazor 添加 HttpClientHandler 以根据请求将 Jwt 添加到 HTTP Header
Blazor Adding HttpClientHandler to add Jwt to HTTP Header on requests
我将 Visual Studio 2019
和 .Net Core 3.0.0-preview-7
与标准 Blazor 客户端、服务器和共享模板一起使用。
在应用程序中,我们的服务器端 WebApi 应用程序将始终需要 JWT 令牌出现在 header 中以进行授权。
从下面看
Make HTTP requests using IHttpClientFactory in ASP.NET Core
我创建了以下处理程序;
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);
}
}
我使用 Blazored.LocalStorage
从 localstorage 获取保存的令牌并将其添加到 header。
现在,此时我不确定该怎么做,就好像我将以下内容添加到 Blazor.Client
Startup.cs
;
services.AddTransient<JwtTokenHeaderHandler>();
services.AddHttpClient("JwtTokenHandler")
.AddHttpMessageHandler<JwtTokenHeaderHandler>();
我收到错误消息;
'IServiceCollection' does not contain a definition for 'AddHttpClient'
and no accessible extension method 'AddHttpClient' accepting a first
argument of type 'IServiceCollection' could be found (are you missing
a using directive or an assembly reference?)
任何人都可以指出我在这里做错了什么吗?
您需要包含 AddHttpClient 方法的 NuGet 包 Microsoft.Extensions.Http
。使用以下命令安装它:Install-Package Microsoft.Extensions.Http -Version 3.0.0-preview7.19362.4
看起来,这个 NuGet 包是在服务器端 blazor 中自动提供的,但必须在客户端 blazor 中单独安装。
@Matthew Flynn,目前您不能在客户端 Blazor 上使用 IHttpClientFactory。
而且您不必派生自 HttpMessageHandler (DelegatingHandler)。 Blazor 已经做到了。下面是n扩展class扩展HttpClient服务的功能,实现在请求消息的header中添加Jwt token的能力...
ServiceExtensions.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 });
}
}
下面展示了如何调用 Web 上的端点 Api,传递从 localStorage 读取的 Jwt 令牌。 (顺便说一句,none 这些版本受到数据保护)
Index.razor
@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));
}
}
希望这行得通...如果行不通,并且您无法解决错误,请来这里告诉社区...
我找到了一个非常好的教程和示例来演示这一点(完成基于 roles/policy 的声明):
https://chrissainty.com/securing-your-blazor-apps-authentication-with-clientside-blazor-using-webapi-aspnet-core-identity/
下面是一段摘录,在默认 http 客户端(通过 DI)上设置默认请求 headers。所有对您网站 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")));
}
// ...
}
以下将 X-CSRF-TOKEN header 添加到 http 请求:
public class CustomHttpMessageHandler : DelegatingHandler
{
private readonly IJSRuntime _js;
public CustomHttpMessageHandler(IJSRuntime js)
{
_js = js;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var afrt = await _js.InvokeAsync<string>("getCookie", ".AFRT");
request.Headers.Add("X-CSRF-TOKEN", afrt);
return await base.SendAsync(request, cancellationToken);
}
}
在Program.cs中配置如下:
builder.Services.AddScoped<CustomHttpMessageHandler>();
builder.Services.AddHttpClient("ApiClient", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<CustomHttpMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("ApiClient"));
您需要将 Microsoft.Extensions.Http 包安装到您的 blazor webassembly 客户端。
我将 Visual Studio 2019
和 .Net Core 3.0.0-preview-7
与标准 Blazor 客户端、服务器和共享模板一起使用。
在应用程序中,我们的服务器端 WebApi 应用程序将始终需要 JWT 令牌出现在 header 中以进行授权。
从下面看
Make HTTP requests using IHttpClientFactory in ASP.NET Core
我创建了以下处理程序;
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);
}
}
我使用 Blazored.LocalStorage
从 localstorage 获取保存的令牌并将其添加到 header。
现在,此时我不确定该怎么做,就好像我将以下内容添加到 Blazor.Client
Startup.cs
;
services.AddTransient<JwtTokenHeaderHandler>();
services.AddHttpClient("JwtTokenHandler")
.AddHttpMessageHandler<JwtTokenHeaderHandler>();
我收到错误消息;
'IServiceCollection' does not contain a definition for 'AddHttpClient' and no accessible extension method 'AddHttpClient' accepting a first argument of type 'IServiceCollection' could be found (are you missing a using directive or an assembly reference?)
任何人都可以指出我在这里做错了什么吗?
您需要包含 AddHttpClient 方法的 NuGet 包 Microsoft.Extensions.Http
。使用以下命令安装它:Install-Package Microsoft.Extensions.Http -Version 3.0.0-preview7.19362.4
看起来,这个 NuGet 包是在服务器端 blazor 中自动提供的,但必须在客户端 blazor 中单独安装。
@Matthew Flynn,目前您不能在客户端 Blazor 上使用 IHttpClientFactory。
而且您不必派生自 HttpMessageHandler (DelegatingHandler)。 Blazor 已经做到了。下面是n扩展class扩展HttpClient服务的功能,实现在请求消息的header中添加Jwt token的能力...
ServiceExtensions.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 });
}
}
下面展示了如何调用 Web 上的端点 Api,传递从 localStorage 读取的 Jwt 令牌。 (顺便说一句,none 这些版本受到数据保护)
Index.razor
@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));
}
}
希望这行得通...如果行不通,并且您无法解决错误,请来这里告诉社区...
我找到了一个非常好的教程和示例来演示这一点(完成基于 roles/policy 的声明): https://chrissainty.com/securing-your-blazor-apps-authentication-with-clientside-blazor-using-webapi-aspnet-core-identity/
下面是一段摘录,在默认 http 客户端(通过 DI)上设置默认请求 headers。所有对您网站 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")));
}
// ...
}
以下将 X-CSRF-TOKEN header 添加到 http 请求:
public class CustomHttpMessageHandler : DelegatingHandler
{
private readonly IJSRuntime _js;
public CustomHttpMessageHandler(IJSRuntime js)
{
_js = js;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var afrt = await _js.InvokeAsync<string>("getCookie", ".AFRT");
request.Headers.Add("X-CSRF-TOKEN", afrt);
return await base.SendAsync(request, cancellationToken);
}
}
在Program.cs中配置如下:
builder.Services.AddScoped<CustomHttpMessageHandler>();
builder.Services.AddHttpClient("ApiClient", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<CustomHttpMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("ApiClient"));
您需要将 Microsoft.Extensions.Http 包安装到您的 blazor webassembly 客户端。