使用来自 Windows 服务的身份进行 HubConnection 身份验证

HubConnection Authentication Using Identity From Windows Service

我有一个提供近乎实时数据的集线器。我希望实时数据的提供者能够向所有连接的客户端发送消息。我 运行 遇到的问题是对连接进行身份验证,因为提供程序是 Windows 服务。所以,我正在使用 HubConnectionBuilder 创建一个客户端。当我尝试连接时,出现 401 身份验证失败,这在意料之中。

我正在尝试弄清楚如何使用共享 Entity Framework 数据库中存在的现有身份验证。有没有办法从这个独立服务中使用 UserManager 或 SigninManager 获取身份验证令牌?或者是否有更好的方法允许 HubConnection 进行身份验证?

这是我使用的连接代码:

var notifyConnection = new HubConnectionBuilder()
    .WithUrl("https://localhost:5001/notify", options =>
    {
        options.AccessTokenProvider = () => Task.FromResult(_myAccessToken);
    })
    .WithAutomaticReconnect()
    .Build();

notifyConnection.Closed += async (error) =>
{
    if (Debug) _logger.LogInformation("Hub connection closed: " + error.Message);
    await Task.Delay(new Random().Next(0, 5) * 1000);
    await notifyConnection.StartAsync();
};
try
{
    var task = notifyConnection.StartAsync();
    task.Wait();
}
catch (Exception ex)
{
    if (Debug) _logger.LogInformation("Hub connection start error: " + ex.Message);
}

_myAccessToken 未定义。我正在尝试弄清楚如何获得可以正确验证的有效访问令牌。

编辑:

我试过添加 JWT 身份验证。我可以验证不记名令牌是否已正确生成。但它似乎并未在 Hub.

上得到验证

我已将以下内容添加到服务配置中:

var key = new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes(Configuration["JwtKey"]));
services.AddAuthentication().AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        LifetimeValidator = (before, expires, token, parameters) =>
            expires > DateTime.UtcNow,
        ValidateAudience = false,
        ValidateIssuer = false,
        ValidateActor = false,
        ValidateLifetime = true,
        IssuerSigningKey = key,
        NameClaimType = ClaimTypes.NameIdentifier
    };

    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            var accessToken = context.Request.Query["access_token"];
            if (!string.IsNullOrEmpty(accessToken))
            {
                context.Token = accessToken;
            }
            return Task.CompletedTask;
        }
    };
});

services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build(); 
    options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
        {
            policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
            policy.RequireClaim(ClaimTypes.NameIdentifier);
        });
});

我还更新了 HubConnectionBuilder 以使用:

notifyConnection = new HubConnectionBuilder()
  .WithUrl(baseUrl + "/notify", options =>
  {
      options.AccessTokenProvider = async () =>
      {
          var stringData = JsonConvert.SerializeObject(new { username = "****", password = "****" });
          var content = new StringContent(stringData);
          content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
          var response = await httpClient.PostAsync(baseUrl + "/api/token", content);
          response.EnsureSuccessStatusCode();
          return await response.Content.ReadAsStringAsync();
      };
  })
  .WithAutomaticReconnect()
  .Build();

它仍然是 returns 401。当我试图将 Authorize 属性强制为:

[Authorize(AuthenticationSchemes = "Bearer,Cookies")]

然后 returns 500 错误。

因此,在更改 Hub class 上的 Authorize 属性后,我能够让 JWT 身份验证与 built-in 身份验证一起工作。

这是新的 Authorize 属性:

[Authorize(AuthenticationSchemes = "Bearer,Identity.Application")]

我添加了一个简单的令牌生成 API 控制器来提供 HubConnection。以下资源非常有帮助:

https://www.codemag.com/article/1807061/Build-Real-time-Applications-with-ASP.NET-Core-SignalR