Атрибут SignalR hub Authorize не работает

Я использую SignalR для отправки уведомлений в angular. Но я хочу сделать это для конкретного пользователя. Пользователь вошел в систему с помощью Azure Ad. И у меня есть [Авторизация] на хабе, но авторизация не удалась. Но в моем контроллере все работает нормально.

Что я пробовал до сих пор. Я попробовал эту услугу. AddAuthentication с сайта Microsoft. https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-2.2 Но тогда мой контроллер не может проверить токен, потому что токен не находится в URL но в шапке.

startup.cs:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOptions();

        // Add custom configuration/resource files
        services.ConfigureSettings(Configuration);
        services.Configure<GzipCompressionProviderOptions>(options =>
            options.Level = System.IO.Compression.CompressionLevel.Fastest
        );

        services.AddResponseCompression(options =>
        {
            options.EnableForHttps = true;
            options.Providers.Add<GzipCompressionProvider>();
        });

        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy",
                builder => builder
                    .AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials()
                    .WithOrigins("http://localhost:4200"));
        });

        services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
            .AddAzureADBearer(options => Configuration.Bind("AzureAD", options));           

        services.AddSignalR();

        // Add framework services.
        services.AddMvc(options =>
        {        
            options.Filters.Add(new ValidateModelStateFilter());

        }).AddJsonOptions(options =>
        {
            options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            options.SerializerSettings.ContractResolver =
                new CamelCasePropertyNamesContractResolver();
        });

мой хаб:

 [Authorize]
 public class NotifyHub : Hub<ITypedHubClient>
   {
    public Task SendMessage(string user, string message)
    {

        return Clients.Client(Context.ConnectionId)
               .BroadcastMessage("ReceiveMessage", user, message);
    }

    public Task Log(string email)
    {
        Debug.WriteLine(Context.ConnectionId);

        return Clients.Caller.BroadcastMessage("succes", "string");
    }

    public override Task OnConnectedAsync()
    {

        return base.OnConnectedAsync();
    }
}

угловой сервис SignalR:

private createConnection() {     
   this._hubConnection = new HubConnectionBuilder()  
  .withUrl('https://localhost:44334/notify', { accessTokenFactory: () => { 
   return this.adalSvc.accessToken }  })      
  .build(); 
}  

Я хочу получить пользователя в своем хабе, чтобы я мог сопоставить пользователей с идентификаторами соединений.

3 ответа

Вы не показываете свой using заявления, и я вижу, что вы также используете MVC. Может быть, вы используете неправильный AuthorizeAttribute?

Убедитесь, что вы используете Microsoft.AspNet.SignalR.AuthorizeAttribute а не MVC один.

Проблема с SignalR заключается в том, что он не может изменить заголовок для отправки токена, поэтому

       services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
       .AddAzureADBearer(options => Configuration.Bind("AzureAD", options));  

не работает с SignalR, поскольку токен ожидается в URL-адресе.

Однако следующее работает как с аутентифицированными вызовами API, так и с аутентифицированными соединениями SignalR.

services.AddAuthentication(options = >{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options = >{
   options.RequireHttpsMetadata = false;
   options.SaveToken = true;
   options.Authority = "https://login.microsoftonline.com/" + Configuration["AzureAd:TenantId"];
options.TokenValidationParameters = new TokenValidationParameters() {
    // These need to be set correctly after checking that it works
    ValidateAudience = false,
    ValidateLifetime = false,
    ValidateIssuer = false,
    ValidateIssuerSigningKey = false,
    ValidateActor = false
};
options.Events = new JwtBearerEvents {
    OnMessageReceived = ctx = >{
        if (ctx.Request.Query.ContainsKey("access_token")) 
             ctx.Token = ctx.Request.Query["access_token"];
        return Task.CompletedTask;
    }
};

});

Вы можете проверить это в своем хабе

       public override async Task OnConnectedAsync()
       {
         var Oid = (Context.User.FindFirst(c => 
                   c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
         Debug.WriteLine(Oid);
       }

Оба атрибута [Authorize] для API и SignalR взяты из

using Microsoft.AspNetCore.Authorization;

лучший способ использования авторизации для концентраторов - заставить приложение добавить токен jwt из строки запроса в контекст, и он работает для меня с помощью этого метода.

поместите это в свою программу.cs (точка сети 6):

      builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{



o.TokenValidationParameters = new TokenValidationParameters
{
    ValidIssuer = builder.Configuration["Jwt:Issuer"],
    ValidAudience = builder.Configuration["Jwt:Audience"],
    IssuerSigningKey = new SymmetricSecurityKey
        (Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
    ValidateIssuer = true,
    ValidateAudience = true,
    ValidateLifetime = false,
    ValidateIssuerSigningKey = true
};

o.Events = new JwtBearerEvents
{
    OnMessageReceived = context =>
    {
        var accessToken = context.Request.Query["access_token"];
        if (string.IsNullOrEmpty(accessToken) == false)
        {
            context.Token = accessToken;
        }

        return Task.CompletedTask;
    }
};


});

и мои концентраторы такие, что используют основной метод авторизации asp

       [Microsoft.AspNetCore.Authorization.Authorize]
    public async Task myhub()
    {

       //do anything in your hub

    }

учебник youtube, который помог мне решить эту проблему

Другие вопросы по тегам