c# - 从服务器端 Blazor 应用程序调用 API 时,用户声明始终为空

标签 c# asp.net-core blazor-server-side

我有一个托管 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/

相关文章:

c# - 加速将文本添加到 TextBox

c# - 以更好的方式在.net core web api中上传图像

c# - 文件存在时找不到 VirtualFileResult 文件

c# - 从.net core 2.1中的单例服务注入(inject)作用域服务

c# - 在服务器端 Blazor 中使用 SignInManager

c# - Blazor 全屏

asp.net-core - 升级到预览版 6 后 Blazor 子应用程序 404 错误

c# - 为什么在 C# 方法中需要多个 `await` 语句?

c# - 关于 Josh Smith 的示例应用程序的 MVVM 问题

c# - 字典的多态性