我想做什么
我有一个后端ASP.Net Core Web API,托管在Azure免费计划上(Add default security headers in .Net Core)。
我还有一个客户网站,我希望让它消耗该API。客户端应用程序将不会托管在Azure上,而是将托管在Github Pages或我可以访问的另一个Web托管服务上。因此,域名不匹配。
为了解决这个问题,我需要在Web API端启用CORS,但是我已经尝试了几个小时的所有方法,但它仍然无法工作。
客户端设置方式 这只是一个简单的React.js客户端。我通过Jquery中的AJAX调用API。React网站可以正常工作,所以我知道不是那个问题。我已经确认了Jquery API调用的有效性。以下是我的调用方式:
var apiUrl = "http://andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication";
//alert(username + "|" + password + "|" + apiUrl);
$.ajax({
url: apiUrl,
type: "POST",
data: {
username: username,
password: password
},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
var authenticatedUser = JSON.parse(response);
//alert("Data Loaded: " + authenticatedUser);
if (onComplete != null) {
onComplete(authenticatedUser);
}
},
error: function (xhr, status, error) {
//alert(xhr.responseText);
if (onComplete != null) {
onComplete(xhr.responseText);
}
}
});
我尝试过什么
尝试1 - “正确”的方式
https://learn.microsoft.com/en-us/aspnet/core/security/cors
我完全按照微软网站上的教程进行了操作,尝试了在Startup.cs中启用全局选项、在每个控制器上设置以及在每个Action上尝试。
按照这种方法,跨域可以工作,但仅限于单个控制器上的单个Action(POST到AccountController)。对于其他所有内容,Microsoft.AspNetCore.Cors
中间件都拒绝设置标头。
我通过NUGET安装了Microsoft.AspNetCore.Cors
,版本为1.1.2
以下是我在Startup.cs中的设置方式
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add Cors
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
// Add framework services.
services.AddMvc();
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new CorsAuthorizationFilterFactory("MyPolicy"));
});
...
...
...
}
// This method gets called by the runtime. Use this method to configure
//the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
// Enable Cors
app.UseCors("MyPolicy");
//app.UseMvcWithDefaultRoute();
app.UseMvc();
...
...
...
}
正如您所看到的,我正在按照指示进行操作。我在 MVC 之前两次添加了 Cors,在那不起作用时,我尝试将 [EnableCors("MyPolicy")]
放在每个控制器上。
[Route("api/[controller]")]
[EnableCors("MyPolicy")]
public class AdminController : Controller
尝试2 - 暴力破解
https://andrewlock.net/adding-default-security-headers-in-asp-net-core/
在之前的尝试中,我试了几个小时后,决定尝试通过手动设置头部来进行暴力破解,强制它们在每个响应上运行。我按照这篇关于如何手动添加头部到每个响应的教程进行操作。
这些是我添加的头部:
.AddCustomHeader("Access-Control-Allow-Origin", "*")
.AddCustomHeader("Access-Control-Allow-Methods", "*")
.AddCustomHeader("Access-Control-Allow-Headers", "*")
.AddCustomHeader("Access-Control-Max-Age", "86400")
这些是我尝试过但失败的其他标头
.AddCustomHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE")
.AddCustomHeader("Access-Control-Allow-Headers", "content-type, accept, X-PINGOTHER")
.AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Host, User-Agent, Accept, Accept: application/json, application/json, Accept-Language, Accept-Encoding, Access-Control-Request-Method, Access-Control-Request-Headers, Origin, Connection, Content-Type, Content-Type: application/json, Authorization, Connection, Origin, Referer")
使用这种方法,跨站点标头被正确应用,并显示在我的开发人员控制台和Postman中。然而问题在于,虽然它通过了Access-Control-Allow-Origin检查,但Web浏览器会在(我认为是)Access-Control-Allow-Headers上抛出一些问题,指出415(不支持的媒体类型)。因此,暴力方法也不起作用。
最后
有没有人已经让这个工作了并且可以帮帮我,或者只是能够指导我方向?
编辑
为了使API调用成功,我不得不停止使用JQuery并转而使用纯Javascript的XMLHttpRequest
格式。
尝试1
我成功地让Microsoft.AspNetCore.Cors
按照MindingData的回答工作,除了在Configure
方法中将app.UseCors
放在app.UseMvc
之前。
此外,当与Javascript API解决方案混合使用时,options.AllowAnyOrigin()
用于通配符支持也开始工作了。
尝试2
因此,我设法让尝试2(强制执行)工作……唯一的例外是Access-Control-Allow-Origin
的通配符不起作用,因此我必须手动设置具有访问权限的域。
显然,这并不理想,因为我只希望这个WebAPI向所有人敞开大门,但至少它在一个单独的网站上对我有效,这意味着它是一个开始。
app.UseSecurityHeadersMiddleware(new SecurityHeadersBuilder()
.AddDefaultSecurePolicy()
.AddCustomHeader("Access-Control-Allow-Origin", "http://localhost:3000")
.AddCustomHeader("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, PATCH, DELETE")
.AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Content-Type, Authorization"));