从服务器端Blazor应用调用API时,用户声明始终为空

时间:2020-10-01 07:56:41

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

我有一个.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控制器有关。

我尝试过:

  • 在cookie配置上将HttpClient设置为false,然后通过JSInterop手动检索cookie以附加HttpOnly标头。由于未能在JSInterop抓取Cookie之前开始API调用,因此失败了。
  • 通过HttpClient手动将HttpClient注入我的ApiService
  • 从正在运行的项目中复制启动配置并覆盖我的项目
  • 以各种不同的方式更改已配置服务的顺序
  • 几种不同的cookie配置
  • 创建和使用自定义services.AddHttpClient<IApiService, ApiService>();
  • 遵循官方Microsoft文档中的几本不同指南
  • 查看有关类似问题的无数文章和Stackoverflow问题并尝试提出建议

我还尝试通过以下方式将身份验证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从未为非空而失败。

1 个答案:

答案 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}");
    }
}