【问题标题】:Authorize doesn't work in Signalr of ASP.NET Core 2.1授权在 ASP.NET Core 2.1 的 Signalr 中不起作用
【发布时间】:2018-09-07 05:23:19
【问题描述】:

我已通过关注this tutorial 将我的项目从 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();
    }
}

当我使用 AngularJS 应用程序连接到 ChatHub 时,我期望 MainPolicy 会被调用。但是,OnConnectedAsync() 函数在没有检查请求身份的情况下被调用。

MVC 控制器的策略已成功应用,但 Signalr 的策略没有。

谁能帮帮我?

谢谢,

【问题讨论】:

    标签: asp.net-core asp.net-core-2.0 asp.net-core-webapi asp.net-core-signalr asp.net-core-2.1


    【解决方案1】:

    我将此问题发布到 Signalr github issue page。 这是他们给我的答案。 我试过了,它成功了:

    解决办法是把[Authorize]属性放到ChatHub

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

    分享给不知道的人吧:)

    【讨论】:

    • Authorize 属性的命名空间是什么?
    【解决方案2】:

    我也有同样的问题,关键有四点:

    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 不在标头中发送令牌,而是在查询中发送它们。在 ConfigureServices(IServiceCollection services) 内的 startup.cs 中,您必须配置您的应用程序以从查询中读取令牌并将它们放在标题中。您可以通过这种方式配置您的 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() 中添加默认的 Athuentication 方案 所以每次我必须像这样指定我的授权方案。 [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 hub Authorize attribute doesn't work

    注意:我在 myChat 类中只授权一个方法时遇到问题。我不知道为什么。

    【讨论】:

      猜你喜欢
      • 2020-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多