Авторизация не работает в Signalr ASP.NET Core 2.1

Я обновил свой проект с ASP.Net Core 2.0 до ASP.NET Core 2.1, выполнив это руководство.

Все было хорошо, пока я не применил Signar Core 2.1 к своему проекту.

Это мой Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IAuthorizationHandler, SolidAccountRequirementHandler>();

        services.AddCors(
            options => options.AddPolicy("AllowCors",
                builder =>
                {
                    builder
                        .AllowAnyOrigin()
                        .AllowCredentials()
                        .AllowAnyHeader()
                        .AllowAnyMethod();
                })
        );

        services.AddAuthorization(x =>
        {
            x.AddPolicy("MainPolicy", builder =>
            {
                builder.Requirements.Add(new SolidAccountRequirement());
            });
        });

        services.AddSignalR();

        #region Mvc builder

        var authenticationBuilder = services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme);

        authenticationBuilder.AddJwtBearer(o =>
        {
            // You also need to update /wwwroot/app/scripts/app.js
            o.SecurityTokenValidators.Clear();

            // Initialize token validation parameters.
            var tokenValidationParameters = new TokenValidationParameters();
            tokenValidationParameters.ValidAudience = "audience";
            tokenValidationParameters.ValidIssuer = "issuer";
            tokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("SigningKey"));
            tokenValidationParameters.ValidateLifetime = false;

            o.TokenValidationParameters = tokenValidationParameters;
        });

        // Construct mvc options.
        services.AddMvc(mvcOptions =>
            {
                ////only allow authenticated users
                var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
                    .AddRequirements(new SolidAccountRequirement())
                    .Build();

                mvcOptions.Filters.Add(new AuthorizeFilter(policy));
            })
            .AddJsonOptions(options =>
            {
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); ;

        #endregion
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        //app.UseHttpsRedirection();
        app.UseCors("AllowCors");

        app.UseSignalR(routes =>
        {
            routes.MapHub<ChatHub>("/chathub");
        });

        app.UseMvc();
    }
}

Это мой SolidRequirementHandler

public class SolidAccountRequirementHandler : AuthorizationHandler<SolidAccountRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SolidAccountRequirement requirement)
    {
        context.Succeed(requirement);
        return Task.CompletedTask;
    }
}

Это мой ChatHub.cs:

public class ChatHub : Hub
{
    [Authorize(Policy = "MainPolicy")]
    public override Task OnConnectedAsync()
    {
        return base.OnConnectedAsync();
    }
}

Я ожидал, что MainPolicy будет вызываться, когда я использую приложение AngularJS для подключения к ChatHub. Однако функция OnConnectedAsync() была вызвана без проверки идентичности запроса.

Политика MVC Controller была применена успешно, но Signalr - нет.

Кто-нибудь может мне помочь ?

Спасибо,




Ответы (2)


Я разместил этот вопрос на странице проблемы Signalr github. Вот ответ, который они мне дали. Я попробовал, и это сработало:

Решение состоит в том, чтобы поместить атрибут [Authorize] в ChatHub

[Authorize(Policy = "MainPolicy")]
public class ChatHub : Hub
{
    public override Task OnConnectedAsync()
    {
        return base.OnConnectedAsync();
    }
}

Просто поделитесь тем, кто не знает :)

person Redplane    schedule 04.04.2018
comment
Какое пространство имен атрибута Authorize? - person Dima; 10.05.2018

У меня такая же проблема, есть четыре ключевых момента:

1- В вашем Startup.cs помните об этом порядке внутри Configure(IApplicationBuilder app)

            app.UseRouting();
            app.UseAuthorization( );
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub<myChat>("/chat");
            });

app.UseAuthorization( ); всегда должен быть между app.UseRouting(); и app.UseEndpoints().

2- SignalR не отправляет токены в заголовке, а отправляет их в запросе. В файле startup.cs внутри ConfigureServices(IServiceCollection services). Вы должны настроить приложение таким образом, чтобы оно считывало токены из запроса и помещало их в заголовок. Вы можете настроить свой JWT следующим образом:

  services.AddAuthentication()
            .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateAudience = false,
                    ValidIssuer = [Issuer Site],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes([YOUR SECRET KEY STRING]))
                };
                options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var path = context.Request.Path;
                        var accessToken = context.Request.Query["access_token"];
                        if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/chat"))
                        {
                            
                            context.Request.Headers.Add("Authorization", new[] { $"Bearer {accessToken}" });
                        }
                        return Task.CompletedTask;
                    }
                };
            });

3- Ваш клиент должен отправить токен, когда он хочет установить соединение. Вы можете добавить токен в Query при создании соединения.

var connection = new signalR.HubConnectionBuilder().withUrl(
"http://localhost:5000/chat", {
    skipNegotiation: true,
    transport: signalR.HttpTransportType.WebSockets,
    accessTokenFactory: () => "My Token Is Here"}).build();

4- Я не добавлял схему аттестации по умолчанию внутри services.AddAuthentication() Поэтому каждый раз я должен указывать мою схему авторизации вот так. [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] И, наконец, вы можете защитить свой класс чата вот так

using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication.JwtBearer;

        [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
        public class myChat : Hub
        {
            ///Some functions
        }

Кажется, что использование операторов важно, поэтому убедитесь, что используете правильные. Атрибут авторизации концентратора SignalR не работает

Примечание. У меня проблема с авторизацией только одного метода в классе myChat. Не знаю почему.

person Mohammad Reza    schedule 25.09.2020