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 控制器的策略已成功应用,但 Signalr 的策略没有。

谁能帮帮我?

谢谢,

4

2 回答 2

4

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

解决方案是将[Authorize]属性放在ChatHub

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

分享给不知道的人吧:)

于 2018-04-04T05:54:19.430 回答
2

我有同样的问题,有四个关键的事情:

1- 在您的 Startup.cs 中注意这个 Order 里面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-我没有在里面添加一个默认的 Athuentication 方案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。我不知道为什么。

于 2020-09-25T17:01:43.867 回答