SignalR JWT утверждает, что отсутствует в IUserIdProvider. JWT-носитель OnMessage получил не стреляя - PullRequest
1 голос
/ 30 апреля 2019

Я пытаюсь настроить SignalR с клиентом и сервером .NET.

Мне просто нужен собственный способ предоставления идентификатора подключенного клиента, и, похоже, единственный способ сделать это - заполнить утверждения, являющиеся частью аргумента HubConnectionContext, при реализации интерфейса IUserIdProvider.

На моем клиенте я создаю JWT, который работает как задумано (проверил, что он построен правильно).

На моем сервере я следовал точным инструкциям здесь

Однако обратный вызов OnMessageReceived не срабатывает, и поэтому токен игнорируется, а впоследствии массив утверждений становится пустым в IUserIdProvider.

Стоит отметить, что IUserIdProvider по-прежнему вызывается, когда клиентconnects.

Это мой код генерации JWT на стороне клиента:

        _hubConnection = new HubConnectionBuilder()
            .WithUrl($"{_hubUrl}", options => options.AccessTokenProvider = () =>
            {
                var jwtHandler = new JwtSecurityTokenHandler();
                var credentials = new SigningCredentials(_securityKey, SecurityAlgorithms.HmacSha256);
                var jwt = new JwtSecurityToken(claims: new[] { new Claim("Id", _id) }, signingCredentials: credentials);
                var tokenString = jwtHandler.WriteToken(jwt);
                return Task.FromResult(tokenString);
            })
            .Build();

Это моя функция запуска ConfigureServices:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IUserIdProvider, MyIdProvider>();

        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                LifetimeValidator = (before, expires, token, param) =>
                {
                    return true;
                },
                ValidateAudience = false,
                ValidateIssuer = false,
                ValidateActor = false,
                ValidateLifetime = true,
                IssuerSigningKey = SecurityKey
            };
            options.Events = new JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    // breakpoints never hit...
                    var accessToken = context.Request.Query["access_token"];
                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrWhiteSpace(accessToken) &&
                        path.StartsWithSegments("myHub"))
                    {
                        context.Token = accessToken;
                    }
                    return Task.CompletedTask;
                }
            };
        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.AddSignalR();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc(Version, new OpenApiInfo
            {
                Version = Version,
                Title = Name
            });
        });            
    }

и, наконец, моя реализация IUserIdProvider:

    public class MyIdProvider : IUserIdProvider
{
    public string GetUserId(HubConnectionContext connection)
    {
        var id = connection.User.Claims.First(x => x.Type == "Id").Value;
        return id;
    }
}

Заранее спасибо.

1 Ответ

0 голосов
/ 01 мая 2019

Было несколько проблем, которые мне пришлось решить, чтобы это работало.

Во-первых, для концентратора требуется атрибут [Authorize], иначе OnMessageReceived никогда не будет вызываться.

Во-вторых, яотсутствовал app.UseAuthentication (), который также необходим для правильной работы конвейера.

После внесения этих изменений мои претензии были получены правильно.

...