我有一个托管 WebAPI 和服务器端 Blazor 应用程序的 .NET Core 项目。该应用程序通过 IdentityDbContext
使用默认身份验证和授权。并使用默认的 AuthenticationStateProvider
对于布拉佐尔。由于我希望此应用程序在将来的某个时候可能迁移到客户端 Blazor,因此我一直将服务器端逻辑保留在 API 中并通过 HttpClient
调用它。我已使用 services.AddScoped<HttpClient>();
在启动中手动注入(inject)它
我遇到的问题是,调用 API 时,API Controller 中的用户声明(即 HttpContext.User
)为空。当我说空时,HttpContext.User
object 不为 null,但所有值均为默认值。预期的行为是声明将填充登录用户的身份信息。
奇怪的是,身份cookie .AspNetCore.Identity.Application
存在于浏览器中,并且 AuthenticationStateProvider
中的值服务均符合登录用户的预期。对我来说,这表明在身份验证和身份方面所有内容都已正确配置,并且该问题在某种程度上与 HttpClient
有关。或 Api Controller 。
我已经尝试过:
- 设置
HttpOnly
将 cookie 配置设置为 false 并通过 JSInterop 手动检索 cookie 以附加HttpClient
header 。由于 API 调用在 JSInterop 完成抓取 cookie 之前就开始,因此失败。 - 手动注入(inject)
HttpClient
进入我的ApiService
通过services.AddHttpClient<IApiService, ApiService>();
- 从工作项目复制启动配置并覆盖我的项目
- 以各种不同的方式更改已配置服务的顺序
- 几种不同的 Cookie 配置
- 创建和使用自定义
AuthenticationStateProvider
- 遵循 Microsoft 官方文档中的多个不同指南
- 查看有关类似问题的无数文章和 Stackoverflow 问题并尝试他们的建议
我还尝试手动将身份验证 cookie 添加到 HttpClient
通过以下方式:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<HttpClient>(s =>
{
var httpContextAccessor = s.GetRequiredService<IHttpContextAccessor>();
string authToken = httpContextAccessor.HttpContext.Request.Cookies[".AspNetCore.Identity.Application"];
var client = new HttpClient(new HttpClientHandler
{
UseCookies = false
});
if (authToken != null)
{
client.DefaultRequestHeaders.Add("Cookie", $".AspNetCore.Identity.Application={authToken}");
}
var request = httpContextAccessor.HttpContext.Request;
client.BaseAddress = new Uri($"{request.Scheme}://{request.Host}/");
return client;
});
此解决方案失败,显示为 httpContextAccessor
调用委托(delegate)时返回 null。我知道没有带有 SignalR 连接的 HttpContext,但是,当首次加载应用程序、刷新页面或进行 API 调用时,我仍然期望有 HttpContext。我还尝试了一个空检查版本,只有在 HttpContext
时才会继续。是非空的,但也失败了 HttpContext
从来都不是非空的。
最佳答案
我能够通过将身份验证 token 直接传递到 Blazor 应用程序,然后将其添加到 HttpClient
来解决此问题。
虽然我的应用程序托管在 MVC View 中,但我知道托管 Blazor 应用程序的最常见方法是通过 Razor 页面。对于遇到此问题的其他人,Razor 页面修改如下。
_Host.cshtml
@{
var token = HttpContext.Request.Cookies[".AspNetCore.Identity.Application"];
}
<app>
<component type="typeof(App)" param-Token="token" render-mode="ServerPrerendered" />
</app>
MVC 解决方案涉及在 Controller 级别获取 token 并将其向下传递。其代码如下。
HomeController.cs
[HttpGet]
public IActionResult Index()
{
var token = HttpContext.Request.Cookies[".AspNetCore.Identity.Application"];
return View(token);
}
Index.cshtml
@model string
...
<app>
<component type="typeof(App)" param-Token="@Model" render-mode="ServerPrerendered" />
</app>
最后,无论上面使用哪种方法,Blazor 应用都会被修改为将 token 添加到 HttpClient
,如下所示。
App.razor
@inject HttpClient HttpClient
...
@code
{
[Parameter] public string Token { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
HttpClient.DefaultRequestHeaders.Add("Cookie", $".AspNetCore.Identity.Application={Token}");
}
}
关于c# - 从服务器端 Blazor 应用程序调用 API 时,用户声明始终为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64151206/