.NET Core UseCors() 不添加 headers
.NET Core UseCors() does not add headers
这将是 How does Access-Control-Allow-Origin header work? 的副本,但那里的方法也不适合我。我希望我只是遗漏了一些东西。
我正在尝试从我的 .NET Core Web API 的响应中获得 Access-Control-Allow-Origin
header,我正在通过 AJAX.[=22 访问它=]
我已经尝试了几种方法。所有,除非另有说明,都在 Startup.cs
文件中。
方法一
public void ConfigureServices(IServiceCollection services)
{
// Add database
services.AddDbContext<DbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DbConnection")));
// Add the ability to use the API with JSON
services.AddCors();
// Add framework services.
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetService<DbContext>().Database.Migrate();
serviceScope.ServiceProvider.GetService<DbContext>().EnsureSeedData();
}
}
app.UseCors(builder => builder.WithOrigins("https://localhost:44306").AllowAnyMethod());
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
Audience = Configuration["Authentication:AzureAd:Audience"],
});
app.UseMvc();
}
方法二
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddCors(options => options.AddPolicy("AllowWebApp",
builder => builder.AllowAnyMethod()
.AllowAnyMethod()
.AllowAnyOrigin()));
//.WithOrigins("https://localhost:44306")));
// ...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// ...
app.UseCors("AllowWebApp");
// ...
}
我也尝试在控制器和方法上添加 [EnableCors("AllowWebApp")]
。
从 Postman 那里,我得到:
content-encoding → gzip
content-type → text/plain; charset=utf-8
date → Wed, 25 Jan 2017 04:51:48 GMT
server →Kestrel
status → 200
vary → Accept-Encoding
x-powered-by → ASP.NET
x-sourcefiles → =?UTF-8?B?[REDACTED]
我也在 Chrome 中尝试过,得到了类似的 headers。
如果重要的话,我尝试访问的方法有一个 Authorize
属性。但是那部分应该工作正常(我至少得到了很好的回应)
那么,我是不是遗漏了一些非常明显的东西,还是它坏了?我目前 运行 版本 1.1.0.
编辑添加 JS 和控制器存根
function getContactPreviews(resultsCallback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = () => {
if (xmlhttp.readyState == XMLHttpRequest.DONE && xmlhttp.status == 200) {
resultsCallback(JSON.parse(xmlhttp.response));
}
}
xmlhttp.open("GET", "https://localhost:44357/api/User/ContactsPreview", true);
xmlhttp.setRequestHeader("Authorization", "Bearer " + localStorage.getItem("AuthorizationToken"));
xmlhttp.send();
}
控制器存根
[Authorize]
[Route("api/[controller]")]
public class UserController : ApiController
{
[HttpGet(nameof(ContactsPreview))]
[EnableCors("AllowWebApp")]
public IEnumerable<Customer> ContactsPreview()
{
// ...
}
}
问题是,当使用 Bearer 身份验证(或任何我想象的)时,它会添加一个 header "Authorization",并且服务器只会在设置允许的情况下给出一个好的 header.
有两种方法可以解决这个问题,下面是只需要代码。它进入 Web API 解决方案中 Startup.cs
中的 Configure()
方法。
方法一:允许所有headers
app.UseCors(builder => builder.WithOrigins("https://localhost:44306")
.AllowAnyMethod()
.AllowAnyHeader());
方法二:允许特定的headers
app.UseCors(builder => builder.WithOrigins("https://localhost:44306")
.AllowAnyMethod()
.WithHeaders("authorization", "accept", "content-type", "origin"));
额外的 header 是因为,根据文档:
Browsers are not entirely consistent in how they set Access-Control-Request-Headers. If you set headers to anything other than "*", you should include at least "accept", "content-type", and "origin", plus any custom headers that you want to support.
Access-Control-Allow-Origin header 仅在以下情况下返回:
- 请求包含 "Origin" header.
- 请求的来源符合 CORS 政策。
然后服务器 returns ACAO-header 以来源 URL 作为值。
Origin header 通常由 XMLHttpRequest object 设置。
有关详细信息,请参阅 How CORS works
在 Startup.cs 文件中,添加以下内容
public CorsPolicy GenerateCorsPolicy(){
var corsBuilder = new CorsPolicyBuilder();
corsBuilder.AllowAnyHeader();
corsBuilder.AllowAnyMethod();
corsBuilder.AllowAnyOrigin(); // For anyone access.
//corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url. Don't add a forward slash on the end!
corsBuilder.AllowCredentials();
return corsBuilder.Build();
}
在 ConfigureServices 方法中:
services.AddCors(options =>
{
options.AddPolicy("AllowAllOrigins", GenerateCorsPolicy());
});
// 在整个应用程序中全局应用 CORS
// 在配置方法中,添加
app.UseCors("AllowAllOrigins");
[禁用Cors]
使用 DisableCors 属性,我们可以为控制器或操作禁用 CORS。
//启用 CORS 控制器基础 - 如果你在全球范围内申请,你不需要这个。
[EnableCors("AllowAllOrigins")]
public class HomeController: Controller {}
截至 2019 年 3 月 17 日,.NET Core 版本 2.1:
这可能会为其他可怜的人节省一些时间...在某些时候,我开始感到沮丧,几乎放弃了将 .NET Core WebApi 作为一个单独的项目。
在现实生活中,启动函数中还有其他配置,例如我有 Swagger、DI 注册等。直到我将 AddCors() 和 UseCors() 方法都放在配置函数中第一个被调用的方法之前,我无法使该死的东西工作。
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("SomePolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("SomePolicy");
之后,来自 Angular 6 应用程序的调用(Swagger Typescript 客户端调用)开始发挥作用。
我想为那些可能已遵循上述建议但仍然无效的人增加一种可能性。在我的例子中,由于管道中的注册顺序,我没有得到 header 返回(或仅在第一次请求时得到它)。
我更改了顺序:
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseCors("WideOpen");
app.UseMvc();
为此:
app.UseCors("WideOpen");
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseMvc();
这解决了我的问题。
我今天在这个问题上浪费了 小时,才发现这是因为如果您使用启用 CORS 的端点路由 RequirePolicy 方法,.Net Core 3 不支持预检 OPTIONS 请求!
official documentation确实提到了这一点,但没有在明显的警告块中指出,所以我完全错过了。
以下将解决该问题,但它会应用全局 CORS 策略,所以买者自负!
服务配置:
public void ConfigureServices(IServiceCollection services)
{
string[] corsOrigins = Configuration.GetSection("AllowedHosts").Get<string[]>();
services.AddCors(options =>
{
options.AddPolicy("AllowConfiguredOrigins", builder => builder
.WithOrigins(corsOrigins)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
);
});
...
基本上,不要这样做:
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors("AllowConfiguredOrigins");
});
...
...改为这个
配置()
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors("AllowConfiguredOrigins");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
...
在 Startup.cs
的末尾 ConfigureServices()
添加:
services.AddCors();
然后在 Configure()
顶部 添加:
app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("*"));
// alternatively you could use .With... methods to specify your restrictions:
// app.UseCors(x => x.WithOrigins("http://domain1.com").WithMethods("GET","POST").WithHeaders("Authorization").WithExposedHeaders("*"));
这将是 How does Access-Control-Allow-Origin header work? 的副本,但那里的方法也不适合我。我希望我只是遗漏了一些东西。
我正在尝试从我的 .NET Core Web API 的响应中获得 Access-Control-Allow-Origin
header,我正在通过 AJAX.[=22 访问它=]
我已经尝试了几种方法。所有,除非另有说明,都在 Startup.cs
文件中。
方法一
public void ConfigureServices(IServiceCollection services)
{
// Add database
services.AddDbContext<DbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DbConnection")));
// Add the ability to use the API with JSON
services.AddCors();
// Add framework services.
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetService<DbContext>().Database.Migrate();
serviceScope.ServiceProvider.GetService<DbContext>().EnsureSeedData();
}
}
app.UseCors(builder => builder.WithOrigins("https://localhost:44306").AllowAnyMethod());
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
Audience = Configuration["Authentication:AzureAd:Audience"],
});
app.UseMvc();
}
方法二
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddCors(options => options.AddPolicy("AllowWebApp",
builder => builder.AllowAnyMethod()
.AllowAnyMethod()
.AllowAnyOrigin()));
//.WithOrigins("https://localhost:44306")));
// ...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// ...
app.UseCors("AllowWebApp");
// ...
}
我也尝试在控制器和方法上添加 [EnableCors("AllowWebApp")]
。
从 Postman 那里,我得到:
content-encoding → gzip
content-type → text/plain; charset=utf-8
date → Wed, 25 Jan 2017 04:51:48 GMT
server →Kestrel
status → 200
vary → Accept-Encoding
x-powered-by → ASP.NET
x-sourcefiles → =?UTF-8?B?[REDACTED]
我也在 Chrome 中尝试过,得到了类似的 headers。
如果重要的话,我尝试访问的方法有一个 Authorize
属性。但是那部分应该工作正常(我至少得到了很好的回应)
那么,我是不是遗漏了一些非常明显的东西,还是它坏了?我目前 运行 版本 1.1.0.
编辑添加 JS 和控制器存根
function getContactPreviews(resultsCallback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = () => {
if (xmlhttp.readyState == XMLHttpRequest.DONE && xmlhttp.status == 200) {
resultsCallback(JSON.parse(xmlhttp.response));
}
}
xmlhttp.open("GET", "https://localhost:44357/api/User/ContactsPreview", true);
xmlhttp.setRequestHeader("Authorization", "Bearer " + localStorage.getItem("AuthorizationToken"));
xmlhttp.send();
}
控制器存根
[Authorize]
[Route("api/[controller]")]
public class UserController : ApiController
{
[HttpGet(nameof(ContactsPreview))]
[EnableCors("AllowWebApp")]
public IEnumerable<Customer> ContactsPreview()
{
// ...
}
}
问题是,当使用 Bearer 身份验证(或任何我想象的)时,它会添加一个 header "Authorization",并且服务器只会在设置允许的情况下给出一个好的 header.
有两种方法可以解决这个问题,下面是只需要代码。它进入 Web API 解决方案中 Startup.cs
中的 Configure()
方法。
方法一:允许所有headers
app.UseCors(builder => builder.WithOrigins("https://localhost:44306")
.AllowAnyMethod()
.AllowAnyHeader());
方法二:允许特定的headers
app.UseCors(builder => builder.WithOrigins("https://localhost:44306")
.AllowAnyMethod()
.WithHeaders("authorization", "accept", "content-type", "origin"));
额外的 header 是因为,根据文档:
Browsers are not entirely consistent in how they set Access-Control-Request-Headers. If you set headers to anything other than "*", you should include at least "accept", "content-type", and "origin", plus any custom headers that you want to support.
Access-Control-Allow-Origin header 仅在以下情况下返回:
- 请求包含 "Origin" header.
- 请求的来源符合 CORS 政策。
然后服务器 returns ACAO-header 以来源 URL 作为值。
Origin header 通常由 XMLHttpRequest object 设置。
有关详细信息,请参阅 How CORS works
在 Startup.cs 文件中,添加以下内容
public CorsPolicy GenerateCorsPolicy(){
var corsBuilder = new CorsPolicyBuilder();
corsBuilder.AllowAnyHeader();
corsBuilder.AllowAnyMethod();
corsBuilder.AllowAnyOrigin(); // For anyone access.
//corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url. Don't add a forward slash on the end!
corsBuilder.AllowCredentials();
return corsBuilder.Build();
}
在 ConfigureServices 方法中:
services.AddCors(options =>
{
options.AddPolicy("AllowAllOrigins", GenerateCorsPolicy());
});
// 在整个应用程序中全局应用 CORS // 在配置方法中,添加
app.UseCors("AllowAllOrigins");
[禁用Cors]
使用 DisableCors 属性,我们可以为控制器或操作禁用 CORS。
//启用 CORS 控制器基础 - 如果你在全球范围内申请,你不需要这个。
[EnableCors("AllowAllOrigins")]
public class HomeController: Controller {}
截至 2019 年 3 月 17 日,.NET Core 版本 2.1:
这可能会为其他可怜的人节省一些时间...在某些时候,我开始感到沮丧,几乎放弃了将 .NET Core WebApi 作为一个单独的项目。
在现实生活中,启动函数中还有其他配置,例如我有 Swagger、DI 注册等。直到我将 AddCors() 和 UseCors() 方法都放在配置函数中第一个被调用的方法之前,我无法使该死的东西工作。
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("SomePolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("SomePolicy");
之后,来自 Angular 6 应用程序的调用(Swagger Typescript 客户端调用)开始发挥作用。
我想为那些可能已遵循上述建议但仍然无效的人增加一种可能性。在我的例子中,由于管道中的注册顺序,我没有得到 header 返回(或仅在第一次请求时得到它)。
我更改了顺序:
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseCors("WideOpen");
app.UseMvc();
为此:
app.UseCors("WideOpen");
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseMvc();
这解决了我的问题。
我今天在这个问题上浪费了 小时,才发现这是因为如果您使用启用 CORS 的端点路由 RequirePolicy 方法,.Net Core 3 不支持预检 OPTIONS 请求!
official documentation确实提到了这一点,但没有在明显的警告块中指出,所以我完全错过了。
以下将解决该问题,但它会应用全局 CORS 策略,所以买者自负!
服务配置:
public void ConfigureServices(IServiceCollection services)
{
string[] corsOrigins = Configuration.GetSection("AllowedHosts").Get<string[]>();
services.AddCors(options =>
{
options.AddPolicy("AllowConfiguredOrigins", builder => builder
.WithOrigins(corsOrigins)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
);
});
...
基本上,不要这样做:
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors("AllowConfiguredOrigins");
});
...
...改为这个
配置()
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors("AllowConfiguredOrigins");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
...
在 Startup.cs
的末尾 ConfigureServices()
添加:
services.AddCors();
然后在 Configure()
顶部 添加:
app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("*"));
// alternatively you could use .With... methods to specify your restrictions:
// app.UseCors(x => x.WithOrigins("http://domain1.com").WithMethods("GET","POST").WithHeaders("Authorization").WithExposedHeaders("*"));