2
votes

I am working on asp.net core signalr 1.1.0 under asp.net core 2.2 version. I want to
make the cross-domain request for web client and as well as a mobile client. When I send request from javascript client, then this request blocked, and below error shows, (index):1 Access to XMLHttpRequest at 'https://localhost:44373/chatHub/negotiate?token=12' from origin 'https://localhost:44381' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

My Javascript client code

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

Signalr core service startup class code

 // 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") its worked, but this is specific for this origin , I want to make AllowAnyOrigin()??

2
Do you have any business case where you would like to allow any origin for it? It shouldn't be an issue to have an appsetting field for your origin configuration. You can also specify a list of origins which can also bit sticked to the appsetting. Wouldn't that work for you?Carlos Torrecillas
Yes, i want to use signalr core for web and as well as mobile clients, so for mobile clients, we can not give any origin?But how i can make it open cross domain connection. as it was in asp.net signalrAli

2 Answers

0
votes

I got it working this way

On Configure services at the top

 services.AddCors();

and in the Configure method

 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()
           );

Whole code can be found here. This used to work just fine for me. I haven't opened it lately though

Github Repo

0
votes

I see two issues with your code. Let's tackle them one by one.

  1. Allowing all origins for the entire application even though you need it only for the SignalR connection. Consider the below code if you want to apply CORS policy only for the signalR endpoint

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapHub<UsersHub>("/UsersHub")
                .RequireCors((policyBuilder) => policyBuilder
                     .WithOrigins("clientUrls")
                     .AllowAnyMethod()
                     .AllowAnyHeader()
                     .AllowCredentials()
        });
    
  2. It is recommended to not allow all origins but if you have such a use case then the below workaround can fix your problem. This is the trick of using .SetIsOriginAllowed(_ => true)

                     .SetIsOriginAllowed(_ => true)
                     .AllowAnyMethod()
                     .AllowAnyHeader()
                     .AllowCredentials()
    

Further if you want more information, have a look at this guide for more details.