我有一个.NET Core项目,该项目承载一个WebAPI和一个服务器端Blazor应用程序。该应用程序通过IdentityDbContext
使用默认的身份验证和授权,并为Blazor使用默认的AuthenticationStateProvider
。由于我希望该应用程序将来可能在某个时候移至Client Blazor,因此我一直将服务器端逻辑保留在API中,并通过HttpClient
对其进行了调用,我使用{ {1}}
我遇到的问题是,在调用API时,API控制器中的用户声明(即services.AddScoped<HttpClient>();
)为空。当我说空时,HttpContext.User
对象不是null,但是所有值都是默认值。预期的行为是,将使用登录用户的身份信息填充“声明”。
奇怪的是,身份cookie HttpContext.User
存在于浏览器中,并且.AspNetCore.Identity.Application
服务中的值均与登录用户所期望的一样。对我来说,这表明在身份验证和身份方面,所有内容均已正确配置,并且该问题与AuthenticationStateProvider
或Api控制器有关。
我尝试过:
HttpClient
设置为false,然后通过JSInterop手动检索cookie以附加HttpOnly
标头。由于未能在JSInterop抓取Cookie之前开始API调用,因此失败了。HttpClient
手动将HttpClient
注入我的ApiService
services.AddHttpClient<IApiService, ApiService>();
我还尝试通过以下方式将身份验证cookie手动添加到AuthenticationStateProvider
:
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;
});
返回null。我了解不存在带有SignalR连接的HttpContext,但是,我仍然希望在首次加载应用程序,刷新页面或进行API调用时使用HttpContext。我还尝试了此操作的空检查版本,该版本仅在httpContextAccessor
为非空时才可以执行,但是由于HttpContext
从未为非空而失败。
答案 0 :(得分:0)
我能够通过将身份验证令牌直接传递到Blazor应用程序,然后以这种方式将其添加到HttpClient
来解决此问题。
虽然我的应用程序托管在MVC视图中,但我了解托管Blazor应用程序的最常见方法是通过Razor Page。对于其他遇到此问题的人,Razor Page修改如下。
_Host.cshtml
@{
var token = HttpContext.Request.Cookies[".AspNetCore.Identity.Application"];
}
<app>
<component type="typeof(App)" param-Token="token" render-mode="ServerPrerendered" />
</app>
MVC解决方案涉及在控制器级别获取令牌并将其向下传递。的代码如下。
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应用程序都将进行修改,以将令牌添加到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}");
}
}