Что я пытаюсь сделать
У меня есть внутренний веб-API ASP.Net Core, размещенный на бесплатном плане Azure (исходный код: https://github.com/killerrin/Portfolio-Backend).
У меня также есть клиентский веб-сайт, который я хочу заставить использовать этот API. Клиентское приложение не будет размещаться в Azure, а будет размещаться на страницах Github или в другой службе веб-хостинга, к которой у меня есть доступ. Из-за этого доменные имена не будут выстраиваться.
Глядя на это, мне нужно включить CORS на стороне Web API, однако я уже несколько часов пробовал все, и он отказывается работать.
Как у меня есть установка клиента Это просто простой клиент, написанный на React.js. Я вызываю API через AJAX в Jquery. Сайт React работает, поэтому я знаю, что это не так. Вызов API Jquery работает, как я подтвердил в Попытке 1. Вот как я делаю вызовы
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://docs.microsoft.com/en-us/aspnet/core/security/cors
Я следовал этому руководству на веб-сайте Microsoft до T, пробуя все 3 варианта включения его в глобальном масштабе в Startup.cs, настраивая его на каждом контроллере и пробуя его на каждом действии.
Следуя этому методу, кросс-домен работает, но только на одном действии на одном контроллере (POST для AccountController). Во всем остальном промежуточное ПО Microsoft.AspNetCore.Cors
отказывается устанавливать заголовки.
Я установил Microsoft.AspNetCore.Cors
через NUGET и версия 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();
...
...
...
}
Как видите, я делаю все как было сказано. Я добавляю Cors перед MVC оба раза, и когда это не сработало, я попытался поместить [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
, веб-браузер бросает шипящее соответствие (я полагаю) Access-Control-Allow-Headers
заявляя 415 (Unsupported Media Type)
Так что метод грубой силы тоже не работает
в заключение
Кто-нибудь заставил это сработать и мог бы протянуть руку или просто указать мне правильное направление?
РЕДАКТИРОВАТЬ
Таким образом, чтобы выполнить вызовы API, мне пришлось прекратить использовать JQuery и переключиться на формат Pure Javascript XMLHttpRequest
.
Попытка 1
Мне удалось заставить работать Microsoft.AspNetCore.Cors
, следуя ответу MindingData, за исключением метода Configure
app.UseCors
перед app.UseMvc
.
Кроме того, при смешивании с параметрами Javascript API Solution.AllowAnyOrigin 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"));