Search code examples
c#.net-corecorspreflightocelot

How to handle cors policy and preflight requests in Ocelot gateway?


I have an Ocelot gateway that routes and handles my API server request. The problem is that I use CORS Policy in APIs, when a request comes from the web browser to APIs and I need to get preflight request and route to the specific API. Now I can't fix the problem in Ocelot gateway. How could I fix it?

The following code is an API sample:

[EnableCors(origins: "*", headers: "*", methods: "*")]
[Route("api/Balance")]
public GeneralResult<DTOResponse> Post(DTORequest req)
{
    var result = new GeneralResult<DTOResponse>();
    try
    {
    .
    .
    .
    }
    catch (Exception ex)
    }
        return result;
    }
}

Solution

  • I found the solution to my problem after a lot of searching and seeing different examples:

    As you can see in preflight request, if an API is called from the browser side, a preflight request is first sent to ensure the authenticity of the connection between the browser and the server. If we make a request directly to the API, everything is ok, but when we use Ocelot, the story changes a bit. In this case Ocelot has to recognize the preflight type request, which as far as I understand is not done in Ocelot and this has to be handled by the developer. To solve this problem, I first used the following code in the ConfigureServices section:

     public void ConfigureServices(IServiceCollection services)
        {
            services.AddOcelot();
            services.AddCors(o =>
            {
                o.AddPolicy("CorsPolicy", p =>
                {
                    p.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
                });
            });
        }
    

    Then in the Configure section, I added the following code:

     public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseCors("CorsPolicy");
            app.UsePreflightRequestHandler();
        }
    

    As you can see in the code snippet above, I first added CORS Policy settings to the services in the ConfigureServices section and then used it in the configuration section.

    Then, I have added a middleware named UsePreflightRequestHandler, which is used in such a way that when a preflight request with options type is sent from the browser, that request is checked in the middleware and the required headers are added to it. And if the type of request is options, the request is checked in the middleware and the response is given with OK. In this case, the browser has received the appropriate response for the preflight request and the process continues and the main request is sent from the browser.

    public class PreflightRequestMiddleware
    {
        private readonly RequestDelegate Next;
        public PreflightRequestMiddleware(RequestDelegate next)
        {
            Next = next;
        }
        public Task Invoke(HttpContext context)
        {
            return BeginInvoke(context);
        }
        private Task BeginInvoke(HttpContext context)
        {
            context.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
            context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept, Athorization, ActualUserOrImpersonatedUserSamAccount, IsImpersonatedUser" });
            context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "GET, POST, PUT, DELETE, OPTIONS" });
            if (context.Request.Method == HttpMethod.Options.Method)
            {
                context.Response.StatusCode = (int)HttpStatusCode.OK;
                return context.Response.WriteAsync("OK");
            }
            return Next.Invoke(context);
        }
    }
    
    public static class PreflightRequestExtensions
    {
        public static IApplicationBuilder UsePreflightRequestHandler(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<PreflightRequestMiddleware>();
        }
    }