admin管理员组

文章数量:1186457

I have an API project that handles all the logic/data handling for a separate Razor Pages site. I've configured CORS on the API project, and I can now successfully call an endpoint from a page's code file:

public async Task OnGetAsync()
{
    var client = _clientFactory.CreateClient("ApiClient");
    var response = await client.GetAsync("http://localhost:5122/vendors");
    var vendors = await response.Content.ReadAsStringAsync();
    ViewData["Vendors"] = vendors;
}

When I try to consume the same endpoint from a DataTables component, I get blocked by CORS. I'm assuming I need to configure DataTables to adjust how it makes it's ajax call, but I can't find how to make it work.

The error message: Access to XMLHttpRequest at 'http://localhost:5122/vendors?_=1738157999876' from origin 'http://localhost:5256' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

But when I look at the headers, the response header shows the location as http://localhost:5122/Identity/Account/Login?ReturnUrl=%2Fvendors%3F_%3D1738158369219 so I'm assuming it's an authentication issue. As the authentication is configured using cookies, I've tried finding a way to attach the cookie to the js request in the Datatables code, but no matter what I tried I couldn't get it to work (I eventually found an article that said to change the cookie to HttpOnly = false, then read the cookie value and create a new cookie with the required name and value, but that didn't work either).

This is how the authentication on the API is configured:

internal static class IdentityServices
{
    public static IServiceCollection AddIdentityServices(this IServiceCollection services, WebApplicationBuilder builder)
    {
        services.AddDataProtection()
            .PersistKeysToFileSystem(new DirectoryInfo(builder.Environment.ContentRootPath + "/Identity"))
            .SetApplicationName("MarketManager");

        services
            .AddDefaultIdentity<Person>()
            .AddRoles<AppRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        services.ConfigureApplicationCookie(options =>
        {
            options.Cookie.Name = ".MarketManager.SharedCookie";
            options.Cookie.Path = "/";
        });

        services.AddAuthentication();
        services.AddAuthorization();

        services.AddHttpContextAccessor();

        return services;
    }
}

Here is the API configuration:

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowApiOrigin",
        builder =>
        {
            builder.WithOrigins("http://localhost:5256")
                   .AllowAnyHeader()
                   .AllowAnyMethod()
                   .AllowCredentials();
        });
});

var app = builder.Build();

app.UseCors("AllowApiOrigin");

app.MapGroup("/vendors")
    .MapVendors();

app.Run();

And this is how I'm calling the endpoint in JS:

$(document).ready(function () {

    datatable = $('#dataTable').DataTable({
        ajax: {
            url: 'http://localhost:5122/vendors',
            dataType: 'json',
            dataSrc: ''
        },
        columns: [
            { data: 'id' }
        ]
    })
});

The endpoint call:

internal static class VendorEndpoints
{
    public static RouteGroupBuilder MapVendors(this RouteGroupBuilder app)
    {
        app.MapGet("/", GetAllVendorsAsync);

        app.WithTags("Vendors");

        return app;
    }

    public static async Task<IResult> GetAllVendorsAsync(
        [FromServices] ISender sender) =>
            TypedResults.Ok(
                await sender.Send(
                    new GetAllVendors.Query()));
}

I have an API project that handles all the logic/data handling for a separate Razor Pages site. I've configured CORS on the API project, and I can now successfully call an endpoint from a page's code file:

public async Task OnGetAsync()
{
    var client = _clientFactory.CreateClient("ApiClient");
    var response = await client.GetAsync("http://localhost:5122/vendors");
    var vendors = await response.Content.ReadAsStringAsync();
    ViewData["Vendors"] = vendors;
}

When I try to consume the same endpoint from a DataTables component, I get blocked by CORS. I'm assuming I need to configure DataTables to adjust how it makes it's ajax call, but I can't find how to make it work.

The error message: Access to XMLHttpRequest at 'http://localhost:5122/vendors?_=1738157999876' from origin 'http://localhost:5256' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

But when I look at the headers, the response header shows the location as http://localhost:5122/Identity/Account/Login?ReturnUrl=%2Fvendors%3F_%3D1738158369219 so I'm assuming it's an authentication issue. As the authentication is configured using cookies, I've tried finding a way to attach the cookie to the js request in the Datatables code, but no matter what I tried I couldn't get it to work (I eventually found an article that said to change the cookie to HttpOnly = false, then read the cookie value and create a new cookie with the required name and value, but that didn't work either).

This is how the authentication on the API is configured:

internal static class IdentityServices
{
    public static IServiceCollection AddIdentityServices(this IServiceCollection services, WebApplicationBuilder builder)
    {
        services.AddDataProtection()
            .PersistKeysToFileSystem(new DirectoryInfo(builder.Environment.ContentRootPath + "/Identity"))
            .SetApplicationName("MarketManager");

        services
            .AddDefaultIdentity<Person>()
            .AddRoles<AppRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        services.ConfigureApplicationCookie(options =>
        {
            options.Cookie.Name = ".MarketManager.SharedCookie";
            options.Cookie.Path = "/";
        });

        services.AddAuthentication();
        services.AddAuthorization();

        services.AddHttpContextAccessor();

        return services;
    }
}

Here is the API configuration:

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowApiOrigin",
        builder =>
        {
            builder.WithOrigins("http://localhost:5256")
                   .AllowAnyHeader()
                   .AllowAnyMethod()
                   .AllowCredentials();
        });
});

var app = builder.Build();

app.UseCors("AllowApiOrigin");

app.MapGroup("/vendors")
    .MapVendors();

app.Run();

And this is how I'm calling the endpoint in JS:

$(document).ready(function () {

    datatable = $('#dataTable').DataTable({
        ajax: {
            url: 'http://localhost:5122/vendors',
            dataType: 'json',
            dataSrc: ''
        },
        columns: [
            { data: 'id' }
        ]
    })
});

The endpoint call:

internal static class VendorEndpoints
{
    public static RouteGroupBuilder MapVendors(this RouteGroupBuilder app)
    {
        app.MapGet("/", GetAllVendorsAsync);

        app.WithTags("Vendors");

        return app;
    }

    public static async Task<IResult> GetAllVendorsAsync(
        [FromServices] ISender sender) =>
            TypedResults.Ok(
                await sender.Send(
                    new GetAllVendors.Query()));
}
Share Improve this question edited yesterday Trent W asked Jan 26 at 4:03 Trent WTrent W 12 bronze badges 2
  • please add the complete error displayed in the console / alose add Endpoint Code – Mohammad Aghazadeh Commented Jan 26 at 10:40
  • Updated with the endpoint code and exact error message – Trent W Commented Jan 26 at 13:36
Add a comment  | 

2 Answers 2

Reset to default 0

the error is clear :

The error message: Access to XMLHttpRequest at 'http://localhost:5122/vendors?_=1737898473189' from origin 'http://localhost:5256' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

you should add http://localhost:5256 in CORS configuration :

change your code as follows :

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowApiOrigin",
        builder =>
        {
            builder.WithOrigins("http://localhost:2526","http://localhost:5256")
                   .AllowAnyHeader()
                   .AllowAnyMethod()
                   .AllowCredentials();
        });
});

I suggest you could modify the jquery datatable request as below :

$(document).ready(function () {
    datatable = $('#dataTable').DataTable({
        ajax: {
            url: 'http://localhost:5122/vendors',
            dataType: 'json',
            dataSrc: '',
            xhrFields: {
                withCredentials: true  
            }
        },
        columns: [
            { data: 'id' }
        ]
    });
});

From the article, you could find this is an object of fieldName-fieldValue pairs to set on the native XHR object. For example, you can use it to set withCredentials to true for cross-domain requests if needed.

Besides, I suggest you could modify the use CORS middleware order , to make sure the call to UseCors must be placed after UseRouting, but before UseAuthorization.

More details, you could refer to this article.

本文标签: aspnet coreWhy does my CORS configuration still block datatables from consuming an APIStack Overflow