Enable CORS is not working after publishing into IIS

Viewed 10186

I hosted dotnet core 2.2 web api application to local IIS. When i run hosted site, site is working. I am trying to do login from angular, it is not working.

It says Access to XMLHttpRequest at 'http://192.168.43.143:100/Auth/Login' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Note: It was working locally. No CORS policy issue occured

I have added cors policy in ConfigureServices and provide middleware to add UseCors().

public void ConfigureServices(IServiceCollection services)
{
   services.AddCors(c =>  
            {    
                c.AddPolicy("AllowOrigin", options => options.AllowAnyHeader()
                    .AllowAnyMethod().AllowAnyOrigin()
                    .SetIsOriginAllowed((host) => true).AllowCredentials());  
            });

   services.Configure<MvcOptions>(options => {
                options.Filters.Add(new CorsAuthorizationFilterFactory("AllowOrigin"));
            });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseCors("AllowOrigin");
    app.UseMvc();
}

My installed software details are given below,

  • System: Windows 10
  • DotNet Core SDK: 2.2.110 & 3.1.201
  • Windows Server Hosting: 2.2.1

Basic code is given below for your reference.

Dot Net Core Web API:

Program.cs

public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseUrls("http://localhost:4000")
                .UseStartup<Startup>();
    }

StartUp.cs

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.AddCors(c =>
            {
                c.AddPolicy("AllowOrigin",
                    options => options.WithOrigins("*").AllowCredentials().AllowAnyHeader().AllowAnyMethod()
                );
            });

            // DbContext and JWT implementation done

            // Authorization filter added
            
            services.Configure<MvcOptions>(options => {
                options.Filters.Add(new CorsAuthorizationFilterFactory("AllowOrigin"));
            });

            //Dependence Injunction done
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            // app.UseForwardedHeaders();
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // 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.UseAuthentication();  //it is used to authorize jwt tokens
            app.UseDefaultFiles();
            app.UseStaticFiles();
            app.UseHttpsRedirection();
            app.UseCors();
            app.UseMvc();
        }

Hosted Web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\TestAPI.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="InProcess" />
    </system.webServer>
  </location>
</configuration>
<!--ProjectGuid: 9aea96ef-cfc4-4231-9bfb-78f4efec933f-->

launchSettings.json:

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false, 
    "anonymousAuthentication": true, 
    "iisExpress": {
      "applicationUrl": "http://localhost:4000",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      //"launchUrl": "api/values",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "TestAPI": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://localhost:4000/values",
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Angular 7:

Interceptor code is given

const authReq = this.currentuser
      ? request.clone({
        headers: request.headers.set('Authorization', 'Bearer ' + this.currentuser)
          .set('Access-Control-Allow-Origin', '*')
          .set('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE, OPTIONS')
          .set('Content-Type', request.headers.get('content-type') ?
            request.headers.get('content-type') : 'application/json')
      })
      : request.clone({
        headers: request.headers
        .set('Access-Control-Allow-Origin', '*')
          .set('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE, OPTIONS')
          .set('Content-Type', 'application/json')
      });
    return next.handle(authReq).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error.status === 401) {
          // auto logout if 401 response returned from api
          this.authenticationService.logout();
          // tslint:disable-next-line: deprecation
          location.reload(true);
        }
        return throwError(error);
      }));

IIS Configuration image given below enter image description here

2 Answers

I had to move the CORS policy into the web.config file for IIS to manage.

I couldn't persuade AddCors to work at all when hosted by reverse proxy IIS.

After a lot (days and days and days) of trial and error, I resorted to letting IIS manage it. This means that I have to configure CORS in two places (at least not at the same time though) if I ever need to separate my ASP.NET (Net5.0) application, but I doubt that would ever happen (Famous last words...)

I cannot help but wander if this is by design - if IIS purposefully disables the CORS handling in Kestrel? If you think about it, the OPTIONS method hits the IIS public endpoint, gets relayed to the .NET Core hosted application and a go/no-go is transmitted back in the response. This constitutes a two-step call every time a request is made. Now that is a lot of relaying that can be mitigated if handled on the first layer.

I hope this helps in SOME way, if not at least to console you in the knowledge that you are NOT alone.

I tested your code snippet of solving the CORS issue, it works perfectly on my side. My only question is why the default request is sent to the HTTP scheme, instead of the HTTPS service endpoint.

Access to XMLHttpRequest at 'http://192.168.43.143:100/Auth/Login'

As far as I know, Asp.Net Core WebAPI2.2 uses https redirection by default, which may be the cause of the problem.

  app.UseHttpsRedirection();
            //app.UseCors("AllowOrigin");
            app.UseMvc();

Besides, I suggest you try another way to solve the CORS issue.
https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#enable-cors
Such as the below way, we decorate the Values controller with EnableCors attribute to support CORS.
Values Controller.

[Route("api/[controller]")]
    [ApiController]
    [EnableCors("MyPolicy")]
    public class ValuesController : ControllerBase
    {

Startup.cs

        public void ConfigureServices(IServiceCollection services)
        {
           services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddCors(options =>
            {
                options.AddPolicy("MyPolicy", builder =>
                 {
builder.WithOrigins("*").AllowCredentials().AllowAnyHeader().AllowAnyMethod();
                 });
            });
        }
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
     
                app.UseHsts();
            }

            app.UseHttpsRedirection();

            app.UseCors();

            app.UseMvc();
        }

Finally, if we enabled other authentication modes in IIS, such as windows authentication, we had better install the IIS Cors module to support CORS. This is also helpful.
https://blogs.iis.net/iisteam/getting-started-with-the-iis-cors-module
Feel free to let me know if the problem persists.

Related