asp.net signalr core 中的跨域请求不起作用?

Posted

技术标签:

【中文标题】asp.net signalr core 中的跨域请求不起作用?【英文标题】:Cross domain request in asp.net signalr core does not work? 【发布时间】:2019-08-05 03:34:53 【问题描述】:

我正在使用 asp.net core 2.2 版本下的 asp.net core signalr 1.1.0。我想 为 Web 客户端和移动客户端发出跨域请求。 当我从 javascript 客户端发送请求时,此请求被阻止,并显示以下错误, (索引):1 从源 'https://localhost:44381' 访问 XMLHttpRequest 在 'https://localhost:44373/chatHub/negotiate?token=12' 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:'Access-Control-Allow 的值-当请求的凭据模式为“包含”时,响应中的“来源”标头不能是通配符“*”。 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。

我的 Javascript 客户端代码

var connection = new signalR.HubConnectionBuilder().withUrl("https://localhost:44373/chatHub?token="+12).build();

Signalr核心服务启动类代码

 // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        
            services.Configure<CookiePolicyOptions>(options =>
            
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            );
            services.AddCors(options =>
            
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()/*WithOrigins("https://localhost:44381")*/
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
            );

            services.AddSignalR();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            //services.AddCors();

        

        // 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.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            


            app.UseHttpsRedirection();
            app.UseCors("CorsPolicy");

            app.UseSignalR(routes =>
            
                routes.MapHub<ChatHub>("/chatHub");
            );
            //app.UseStaticFiles();
            //app.UseCookiePolicy();
            app.UseMvc();
        


builder.AllowAnyOrigin() its not working 

builder => builder.WithOrigins("https://localhost:44381") 它的工作,但这是特定于这个 origin , 我想做 AllowAnyOrigin()??

【问题讨论】:

您是否有任何商业案例希望允许任何来源?为您的原始配置设置一个 appsetting 字段应该不是问题。您还可以指定一个来源列表,这些来源也可以坚持到应用程序设置。这不适合你吗? 是的,我想为 web 和移动客户端使用 signalr 核心,所以对于移动客户端,我们不能给出任何来源?但是我怎样才能让它打开跨域连接。就像在 asp.net signalr 中一样 【参考方案1】:

我是这样弄的

在顶部配置服务

 services.AddCors();

在配置方法中

 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
    .AddDbContext<ChatContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
            services.Configure<FormOptions>(options =>
            
                options.MultipartBodyLengthLimit = 60000000;
            );
            services.AddMvc().AddJsonOptions(options =>
            
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            );

            services.AddMvcCore()
               .AddAuthorization()
               .AddJsonOptions(options =>
               
                   options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                   options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
               );
            var identityServerAuthOptions = Configuration.GetSection("Identity").Get<IdentityServerAuthenticationOptions>();

            services.AddAuthentication("Bearer")
                .AddIdentityServerAuthentication(options =>
                
                    options.Authority = identityServerAuthOptions.Authority;
                    options.RequireHttpsMetadata = identityServerAuthOptions.RequireHttpsMetadata;
                    options.ApiName = identityServerAuthOptions.ApiName;
                );


            var settings = new JsonSerializerSettings();
            settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            settings.ContractResolver= new CamelCasePropertyNamesContractResolver();
            services.AddSignalR()
                   .AddJsonProtocol(options => 
                       options.PayloadSerializerSettings = settings;
                          );
            services.AddTransient<IUserService, UserService>();
            services.AddCors();
    

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
            //Data.AddData(app.ApplicationServices.GetService<ChatContext>());
            app.Use(async (context, next) =>
            
                if (string.IsNullOrWhiteSpace(context.Request.Headers["Authorization"]))
                
                    if (context.Request.QueryString.HasValue)
                    
                        var token = context.Request.QueryString.Value.Split('&').SingleOrDefault(x => x.Contains("authorization"))?.Split('=')[1];
                        if (!string.IsNullOrWhiteSpace(token))
                        
                            context.Request.Headers.Add("Authorization", new[]  $"Bearer token" );
                        
                    
                
                await next.Invoke();
            );
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
              //  app.UseBrowserLink();
            
            else
            
                app.UseExceptionHandler("/Home/Error");
            

            app.UseStaticFiles();
            app.UseAuthentication();
            app.UseCors(x => x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
            app.UseSignalR(config =>
            

                config.MapHub<UserHub>("/UsersHub");
            );
            app.UseMvc(routes =>
            
                routes.MapRoute(
                    name: "default",
                    template: "controller=Home/action=Index/id?");
                routes.MapSpaFallbackRoute("spa-fallback", new  controller = "Home", action = "Index" );
            );
        
    





  app.UseCors(builder =>
            builder.AllowAnyOrigin()
       .AllowAnyMethod()
       .AllowAnyHeader()
           );

完整的代码可以在这里找到。这过去对我来说很好用。不过最近没打开过

Github Repo

【讨论】:

嗨,npo,我使用了你的代码,但它不起作用,你能把完整的代码发给我吗。 我已经用你的代码更新了启动,但还是不行? @Ali 我刚刚更新了我的答案,包括对我有用的整个事情,还有一个指向整个项目所在的 github 的链接。希望有帮助 好的,谢谢,npo,你能完善你的 git lab 链接吗,它没有打开 谢谢指出,更新了答案。成功了吗?【参考方案2】:

我发现您的代码存在两个问题。让我们一一解决。

    允许整个应用程序的所有来源,即使您只需要 SignalR 连接。如果您只想为 signalR 端点应用 CORS 策略,请考虑以下代码

        app.UseEndpoints(endpoints =>
        
            endpoints.MapControllers();
            endpoints.MapHub<UsersHub>("/UsersHub")
                .RequireCors((policyBuilder) => policyBuilder
                     .WithOrigins("clientUrls")
                     .AllowAnyMethod()
                     .AllowAnyHeader()
                     .AllowCredentials()
        );
    

    建议不要允许所有来源,但如果您有这样的用例,那么以下解决方法可以解决您的问题。这就是使用 .SetIsOriginAllowed(_ => true)

    的技巧
                     .SetIsOriginAllowed(_ => true)
                     .AllowAnyMethod()
                     .AllowAnyHeader()
                     .AllowCredentials()
    

如果您想了解更多信息,请查看guide 了解更多详情。

【讨论】:

以上是关于asp.net signalr core 中的跨域请求不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core SignalR 中的客户端生命周期事件

带有 SignalR 集线器的 ASP.NET Core 中的范围服务

如何在ASP NET Core中实现CORS跨域

在ASP.NET 5应用程序中的跨域请求功能详解

发现 ASP.NET Core SignalR

ASP.NET Core SignalR:集线器Hubs