ThreeMammals / Ocelot

.NET API Gateway
https://www.nuget.org/packages/Ocelot
MIT License
8.4k stars 1.64k forks source link

How implements Cors headers #191

Closed oamm closed 6 years ago

oamm commented 6 years ago

I implementing ocelot in my new project, i create the integration of my services in one point with ocelot but when i try to post, put, path or delete to a resource in my api gateway, the browser show me the message

Failed to load http://localhost:8080/api/prospects: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8888' is therefore not allowed access. The response had HTTP status code 404.

I try to configure cors in gateway installing and implementing the package Microsoft.AspNetCore.Cors

` public void ConfigureServices(IServiceCollection services) { services.AddCors(); services.AddOcelot(Configuration) .AddCacheManager(x => { x.WithMicrosoftLogging(log => { log.AddConsole(Microsoft.Extensions.Logging.LogLevel.Debug); }) .WithDictionaryHandle(); }); ; }

public void Configure(IApplicationBuilder app, IHostingEnvironment env, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    app.UseCors(
        options => options.WithOrigins("http://localhost:8888").AllowAnyMethod()
    );
    app.UseOcelot().Wait();
} 

`

but i don't have any idea to how to do work with ocelot

TomPallister commented 6 years ago

@oamm thanks for your interest in the project.

Have you tried those CORS settings with a normal asp.net core project without Ocelot?

That would help us understand if Ocelot is a problem or if its just the CORS settings?

There is no specific CORS functionality in Ocelot so I expect this should work.

oamm commented 6 years ago

Hi thanks so much for the advice, i tested the configuration directly in one service so i prove the configuration didnt work even without ocelot, so i change the implementation in this way and now is work with ocelot

` public void ConfigureServices(IServiceCollection services) { services.AddOcelot(Configuration) .AddCacheManager(x => { x.WithMicrosoftLogging(log => { log.AddConsole(Microsoft.Extensions.Logging.LogLevel.Debug); }) .WithDictionaryHandle(); }); services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.WithOrigins("http://192.168.1.101:8888") .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); }); }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        app.UseCors("CorsPolicy");
        app.UseOcelot().Wait();
    }

` thanks for the help.

TomPallister commented 6 years ago

@oamm awesome!! No worries glad it worked

ogomaemmanuel commented 6 years ago

@TomPallister Cors work on normal routes but when it comes to aggregate routes It does not work, I am being forced to use fiddler or postman when testing aggregate roots

TomPallister commented 6 years ago

@ogomaemmanuel mmmmm that does not make any sense to me. what is Ocelot returning when making cors request for aggregate?

ogomaemmanuel commented 6 years ago

http://localhost:9008/CheckoutOption: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access.

TomPallister commented 6 years ago

@ogomaemmanuel can you share your json configuration and startup / program.cs?

ogomaemmanuel commented 6 years ago

using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Ocelot.DependencyInjection; using Ocelot.Middleware; using Ocelot.Provider.Polly; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens;

namespace ShoppingCartApiGateWay { 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.AddMvc();
    }

    // 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();
        }
        app.UseMvc();
    }
}

}

ogomaemmanuel commented 6 years ago

{ "ReRoutes": [ //Basket reroutes config { "DownstreamPathTemplate": "/api/Basket", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { "Host": "basketservice", "Port": 80 } ], "UpstreamPathTemplate": "/api/Basket", "UpstreamHttpMethod": [ "Options", "Post", "Get" ]

},
{
  "DownstreamPathTemplate": "/api/Basket/{customerId?}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "basketservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/Basket/{customerId?}",
  "UpstreamHttpMethod": [ "Options", "Get" ]

},

{
  "DownstreamPathTemplate": "/api/Basket/{customerId?}/{itemId}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "basketservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/Basket/{customerId?}/{itemId}",
  "UpstreamHttpMethod": [ "Options", "Put", "Delete" ]
},

//manufacturers  reroutes config
{
  "DownstreamPathTemplate": "/api/Manufacturer",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "manufacturerservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/Manufacturer",
  "UpstreamHttpMethod": [ "Options", "Post", "Get" ]
},
{
  "DownstreamPathTemplate": "/api/Manufacturer/{id}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "manufacturerservice",
      "Port": 9002
    }
  ],
  "UpstreamPathTemplate": "/api/Manufacturer/{id}",
  "UpstreamHttpMethod": [ "Options", "Put", "Get", "Delete" ]
},

// orders reroutes config
{
  "DownstreamPathTemplate": "/api/orders",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "orderservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/orders",
  "UpstreamHttpMethod": [ "Options", "Post", "Get" ]
},

{
  "DownstreamPathTemplate": "/api/orders/{id}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "orderservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/orders/{id}",
  "UpstreamHttpMethod": [ "Options", "Get", "Delete", "Put" ]
},
{
  "DownstreamPathTemplate": "/api/orders/customer/{id}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "orderservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/orders/customer/{id}",
  "UpstreamHttpMethod": [ "Get" ]
},

{
  "DownstreamPathTemplate": "/api/orders/order-items/{id}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "orderservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/orders/order-items/{id}",
  "UpstreamHttpMethod": [ "Options", "Get" ]
},

//payment methods reroute config

{
  "DownstreamPathTemplate": "/api/PaymentMethods",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "paymentmethodservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/PaymentMethods",
  "UpstreamHttpMethod": [ "Options", "Get", "Post" ],
  "Key": "paymentMethods"
},

{
  "DownstreamPathTemplate": "/api/PaymentMethods/{id}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "paymentmethodservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/PaymentMethods/{id}",
  "UpstreamHttpMethod": [ "Options", "Get", "Put", "Delete" ]
  //"AuthenticationOptions": {
  //  "AuthenticationProviderKey": "TestKey",
  //  "AllowedScopes": []
  //}

},

//productcategory services reroutes
{
  "DownstreamPathTemplate": "/api/ProductsCategory",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "productcategoryservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/ProductsCategory",
  "UpstreamHttpMethod": [ "Options", "Get", "Post", "PUt" ]
  //"AuthenticationOptions": {
  //  "AuthenticationProviderKey": "TestKey",
  //  "AllowedScopes": []
  //}
},

{
  "DownstreamPathTemplate": "/api/ProductsCategory/{id}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "productcategoryservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/ProductsCategory/{id}",
  "UpstreamHttpMethod": [ "Options", "Get", "PUt", "Delete" ]

},

//products reroutes settings
{
  "DownstreamPathTemplate": "/api/products/all",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "productservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/products/all",
  "UpstreamHttpMethod": [ "Options", "Get" ]
  //"AuthenticationOptions": {
  //  "AuthenticationProviderKey": "TestKey",
  //  "AllowedScopes": []
  //}
},
{
  "DownstreamPathTemplate": "/api/products/{id}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "productservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/products/{id}",
  "UpstreamHttpMethod": [ "Options", "Get", "Delete" ]
  //"AuthenticationOptions": {
  //  "AuthenticationProviderKey": "TestKey",
  //  "AllowedScopes": []
  //}
},

{
  "DownstreamPathTemplate": "/api/products",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "productservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/products",
  "UpstreamHttpMethod": [ "Options", "Post" ]
  //"AuthenticationOptions": {
  //  "AuthenticationProviderKey": "TestKey",
  //  "AllowedScopes": []
  //}
},

//shipment methods reroutes config
{
  "DownstreamPathTemplate": "/api/ShipmentMethods",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "shipmentmethodservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/ShipmentMethods",
  "UpstreamHttpMethod": [ "Options", "Get", "Post" ],
  "Key": "shipmentMethods"
},
{
  "DownstreamPathTemplate": "/api/ShipmentMethods/{id}",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "shipmentmethodservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/ShipmentMethods/{id}",
  "UpstreamHttpMethod": [ "Options", "Get", "Put", "Delete" ]
  //"AuthenticationOptions": {
  //  "AuthenticationProviderKey": "TestKey",
  //  "AllowedScopes": []
  //}
},

{
  "DownstreamPathTemplate": "/api/MpesaPayment",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "paymentservice",
      "Port": 80
    }
  ],
  "UpstreamPathTemplate": "/api/MpesaPayment",
  "UpstreamHttpMethod": [ "Options", "Post" ]
},

{
  "DownstreamPathTemplate": "/Signalr/NotificationHub/negotiate",
  "UpstreamPathTemplate": "/Signalr/NotificationHub/negotiate",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "signalrnotificationservice",
      "Port": 80
    }
  ],
  "UpstreamHttpMethod": [ "Options", "Get", "Post" ]
},

{
  "DownstreamPathTemplate": "/Signalr/NotificationHub",
  "UpstreamPathTemplate": "/Signalr/NotificationHub",
  "DownstreamScheme": "http",
  "DownstreamHostAndPorts": [
    {
      "Host": "signalrnotificationservice",
      "Port": 80
    }
  ],
  "UpstreamHttpMethod": [ "Options", "Get", "Post" ]
}

], "Aggregates": [ { "ReRouteKeys": [ "paymentMethods", "shipmentMethods" ], "UpstreamPathTemplate": "/CheckoutOption" } ], "GlobalConfiguration": {} }

ogomaemmanuel commented 6 years ago

checkoutoption path works on postman but not on browser

ogomaemmanuel commented 6 years ago

using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; using Ocelot.DependencyInjection; using Ocelot.Middleware; using Ocelot.Provider.Polly; using Microsoft.Extensions.Logging; using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder; using System.IO;

namespace ShoppingCartApiGateWay { public class Program { public static void Main(string[] args) { new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .ConfigureAppConfiguration((hostingContext, config) => { config .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) .AddJsonFile("appsettings.json", true, true) .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) .AddJsonFile("configuration.json") .AddEnvironmentVariables(); }) .ConfigureServices(s => { s.AddOcelot();

           })
           .ConfigureLogging((hostingContext, logging) =>
           {
            //add your logging
        })
           .UseIISIntegration()
           .Configure(app =>
           {
               app.UseOcelot().Wait();
           })
           .Build()
           .Run();
    }
}

}

jducobu commented 6 years ago

Is it possible to implements CORS by application using the file ocelot.json like you configure the "UpstreamHttpMethod": [ "Options", "Get", "Post" ] ?

vankhanhpr commented 4 years ago

I have some problem, so I config my code as above. It's not working and have some error 401. Can anyone show your project. Help help , please!

vankhanhpr commented 4 years ago

app.UseCors("CorsPolicy");

I have some problem with CorsPolicy, can you show your code to help me , please!

RayuduPanasakarla commented 4 years ago

I got solution use below code in startup.cs file

public void ConfigureServices(IServiceCollection services)
{
        services.AddCors();
        services.AddOcelot();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }        

        app.UseCors(builder => builder
                       .AllowAnyOrigin()
                       .AllowAnyMethod()
                       .AllowAnyHeader()
                       .WithExposedHeaders("Content-Disposition"));

        app.UseCors(builder => builder.AllowCredentials());

        app.UseOcelot().Wait();
}
natiox commented 2 years ago

I got solution use below code in startup.cs file

...
        app.UseCors(builder => builder
                       .AllowAnyOrigin()
                       .AllowAnyMethod()
                       .AllowAnyHeader()
                       .WithExposedHeaders("Content-Disposition"));

        app.UseCors(builder => builder.AllowCredentials());
...

Microsoft says: https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#set-the-allowed-origins-1 Specifying AllowAnyOrigin and AllowCredentials is an insecure configuration and can result in cross-site request forgery. The CORS service returns an invalid CORS response when an app is configured with both methods.