Blazor WebAssembly 阻止 WebApi AllowAnonymous
Blazor WebAssembly blocks WebApi AllowAnonymous
我创建了一个 Blazor WebAssembly 项目,并希望为 WebAPI 提供一个 public 可用函数。
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class SystemEvalApiController : ControllerBase
{
public SystemEvalApiController(AppDbContext context, IMapper mapper)
{...}
[Route("LatestEvals")]
[AllowAnonymous]
public ActionResult LatestEvals()
那是我的 Api 控制器,我应该可以调用它:
SystemEvalPublicViewModel = await Http
.GetFromJsonAsync<SystemEvalPublicViewModel>(
HttpService.BuildUrl("api/SystemEvalApi/LatestEvals"));
当我没有登录任何帐户时。但是我得到了这个错误:
info: System.Net.Http.HttpClient.JPB.BorannRemapping.ServerAPI.LogicalHandler[100]
Start processing HTTP request GET https://localhost:44330/api/SystemEvalApi/LatestEvals
blazor.webassembly.js:1 info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed.
看起来"DefaultAuthorizationService"不识别Anonymous属性,但是我找不到直接失败的地方。
如何声明无需登录即可从 HttpClient 访问的 WebAPI 函数。
Microsoft.AspNetCore.Components.WebAssembly.Server 3.2.0.-rc1.20223.4
编辑:
这是 ClientServices 的声明:
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddHttpClient("JPB.BorannRemapping.ServerAPI", client =>
{
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
})
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("JPB.BorannRemapping.ServerAPI"));
builder.Services.AddTransient(e => new HttpService(e.GetService<HttpClient>()));
builder.Services.AddApiAuthorization();
builder.Services.AddBlazoredLocalStorage();
await builder.Build().RunAsync();
因此,每次您获取 HttpClient
时,它都会使用 BaseAddressAuthorizationMessageHandler
来尝试对请求进行身份验证。但在这种情况下,你的请求不应该被验证,所以你可以做类似的事情:
注册
builder.Services.AddHttpClient("JPB.BorannRemapping.ServerAPI.Anonymous", client =>
{
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
});
用法
@inject IHttpClientFactory _factory
@code {
...
var httpClient = _factory.CreateClient("JPB.BorannRemapping.ServerAPI.Anonymous");
var httpService = new HttpService(httpClient);
SystemEvalPublicViewModel = await httpClient
.GetFromJsonAsync<SystemEvalPublicViewModel>(
httpService.BuildUrl("api/SystemEvalApi/LatestEvals"));
}
基于@agua from mars 的回答。
在Program.cs
注册
您可以将 2 个命名的 HttpClient 添加到服务集合(第一个用于经过身份验证的调用,第二个用于匿名):
builder.Services.AddHttpClient("YourProject.ServerAPI",
client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
builder.Services.AddHttpClient("YourProject.ServerAPI.Anonymous",
client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("YourProject.ServerAPI"));
//Register a new service for getting an Anonymous HttpClient
builder.Services.AddScoped<IHttpAnonymousClientFactory, HttpAnonymousClientFactory>();
为依赖注入添加新的接口和实现:
public interface IHttpAnonymousClientFactory
{
HttpClient HttpClient { get; }
}
public class HttpAnonymousClientFactory : IHttpAnonymousClientFactory
{
private readonly IHttpClientFactory httpClientFactory;
public HttpAnonymousClientFactory(IHttpClientFactory httpClientFactory)
{
this.httpClientFactory = httpClientFactory;
}
public HttpClient HttpClient => httpClientFactory.CreateClient("YourProject.ServerAPI.Anonymous");
}
Razor 组件中的用法(用于匿名 HttpClient)
[Inject]
private IHttpAnonymousClientFactory httpAnonymousClientFactory { get; set; }
private MyViewModel myModel;
protected override async Task OnInitializedAsync()
{
myModel = await httpAnonymousClientFactory.HttpClient.GetFromJsonAsync<MyViewModel>($"api/mycontroller/myendpoint");
}
在 Razor 组件中的使用(对于经过身份验证的 HttpClient)
[Inject]
private HttpClient httpClient { get; set; }
private MyOtherViewModel myModel;
protected override async Task OnInitializedAsync()
{
myModel = await httpClient.GetFromJsonAsync<MyOtherViewModel>($"api/mycontroller/mysecureendpoint");
}
我创建了一个 Blazor WebAssembly 项目,并希望为 WebAPI 提供一个 public 可用函数。
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class SystemEvalApiController : ControllerBase
{
public SystemEvalApiController(AppDbContext context, IMapper mapper)
{...}
[Route("LatestEvals")]
[AllowAnonymous]
public ActionResult LatestEvals()
那是我的 Api 控制器,我应该可以调用它:
SystemEvalPublicViewModel = await Http
.GetFromJsonAsync<SystemEvalPublicViewModel>(
HttpService.BuildUrl("api/SystemEvalApi/LatestEvals"));
当我没有登录任何帐户时。但是我得到了这个错误:
info: System.Net.Http.HttpClient.JPB.BorannRemapping.ServerAPI.LogicalHandler[100]
Start processing HTTP request GET https://localhost:44330/api/SystemEvalApi/LatestEvals
blazor.webassembly.js:1 info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed.
看起来"DefaultAuthorizationService"不识别Anonymous属性,但是我找不到直接失败的地方。
如何声明无需登录即可从 HttpClient 访问的 WebAPI 函数。 Microsoft.AspNetCore.Components.WebAssembly.Server 3.2.0.-rc1.20223.4
编辑: 这是 ClientServices 的声明:
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddHttpClient("JPB.BorannRemapping.ServerAPI", client =>
{
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
})
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("JPB.BorannRemapping.ServerAPI"));
builder.Services.AddTransient(e => new HttpService(e.GetService<HttpClient>()));
builder.Services.AddApiAuthorization();
builder.Services.AddBlazoredLocalStorage();
await builder.Build().RunAsync();
因此,每次您获取 HttpClient
时,它都会使用 BaseAddressAuthorizationMessageHandler
来尝试对请求进行身份验证。但在这种情况下,你的请求不应该被验证,所以你可以做类似的事情:
注册
builder.Services.AddHttpClient("JPB.BorannRemapping.ServerAPI.Anonymous", client =>
{
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
});
用法
@inject IHttpClientFactory _factory
@code {
...
var httpClient = _factory.CreateClient("JPB.BorannRemapping.ServerAPI.Anonymous");
var httpService = new HttpService(httpClient);
SystemEvalPublicViewModel = await httpClient
.GetFromJsonAsync<SystemEvalPublicViewModel>(
httpService.BuildUrl("api/SystemEvalApi/LatestEvals"));
}
基于@agua from mars 的回答。
在Program.cs
注册您可以将 2 个命名的 HttpClient 添加到服务集合(第一个用于经过身份验证的调用,第二个用于匿名):
builder.Services.AddHttpClient("YourProject.ServerAPI",
client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
builder.Services.AddHttpClient("YourProject.ServerAPI.Anonymous",
client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("YourProject.ServerAPI"));
//Register a new service for getting an Anonymous HttpClient
builder.Services.AddScoped<IHttpAnonymousClientFactory, HttpAnonymousClientFactory>();
为依赖注入添加新的接口和实现:
public interface IHttpAnonymousClientFactory
{
HttpClient HttpClient { get; }
}
public class HttpAnonymousClientFactory : IHttpAnonymousClientFactory
{
private readonly IHttpClientFactory httpClientFactory;
public HttpAnonymousClientFactory(IHttpClientFactory httpClientFactory)
{
this.httpClientFactory = httpClientFactory;
}
public HttpClient HttpClient => httpClientFactory.CreateClient("YourProject.ServerAPI.Anonymous");
}
Razor 组件中的用法(用于匿名 HttpClient)
[Inject]
private IHttpAnonymousClientFactory httpAnonymousClientFactory { get; set; }
private MyViewModel myModel;
protected override async Task OnInitializedAsync()
{
myModel = await httpAnonymousClientFactory.HttpClient.GetFromJsonAsync<MyViewModel>($"api/mycontroller/myendpoint");
}
在 Razor 组件中的使用(对于经过身份验证的 HttpClient)
[Inject]
private HttpClient httpClient { get; set; }
private MyOtherViewModel myModel;
protected override async Task OnInitializedAsync()
{
myModel = await httpClient.GetFromJsonAsync<MyOtherViewModel>($"api/mycontroller/mysecureendpoint");
}