大家都知道,當某網頁透過 JS 要 Post 另一個網頁時,如果它們是不同 Domain 就會受到 Browser 的安全限制。
而在 ASP.NET 時,因為都 Host 在 IIS 上面,所以可以在 web.config 中去設定 CORS 的標頭。
如果是 ASP.NET Core 是否也相同呢?
當我們將 ASP.NET Core API 專案 Host 在 IIS 上時,再透過另個網域網頁去 POST 它時,就會出現以下的錯誤訊息,
Access to fetch at ‘http://localhost/rmstore/product' from origin ‘http://localhost:56070' has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
這表示我們需要給它 CORS 相關的 Header ,所以在 web.config 中加入 Header 的設定,如下,
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" >
</handlers>
<aspNetCore processPath=".\RMStore.API.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
</system.webServer>
</location>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="*" />
<add name="Access-Control-Allow-Methods" value="*" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders> </httpProtocol> </system.webServer> </configuration>
再測試網頁,這時出現另一個錯誤訊息,如下,
Access to fetch at ‘http://localhost/rmstore/product' from origin ‘http://localhost:56070' has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.
這表示 Browser 在做 prefight 時,回來的 stats 是不對的,所以就使用 Fiddler 試一下,果然是回 405 Method Not Allowed
可是在 Header 中已設定了 Access-Control-Allow-Methods 為 * 了。
所以應該是在 ASP.NET Core 程式中被擋住了,透過程式執行起來,再透過 Fiddler 跑 OPTIONS 也是回 405。
所以必需將預設的 CORS 設定 allow methods ,所以在 StartUp.cs 的 ConfigureServices Method 中,加入設定預設 CORS 的 Allow Methods 設定,
public void ConfigureServices(IServiceCollection services)
{
// other codes....
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.AllowAnyMethod();
});
});
}
在 StartUp.cs 的 Configure Method 中,使用 CORS,
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// other codes...
app.UseCors();
//
}
重新建置後,執行 OPTIONS 就會回 204 ,所以透過網頁來執行就沒問題了。
不過,即然都在程式中設定了,那就直接在程式中設定,而 Allow-Origin 則可以從 appsettings.json 中讀取,
appsettings.json
"Cors": {
"AllowOrigin": "http://localhost:56070, https://localhost:44330"
}
或是 allow all
"Cors": {
"AllowOrigin": "*"
}
而將相關的設定,寫在 StartUp.cs 的 ConfigureServices Method 中,
public void ConfigureServices(IServiceCollection services)
{
// other code....
string[] corsOrigins = Configuration["Cors:AllowOrigin"].Split(',', StringSplitOptions.RemoveEmptyEntrie services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
if (corsOrigins.Contains("*"))
{
builder.SetIsOriginAllowed(_ => true);
}
else
{
builder.WithOrigins(corsOrigins);
}
builder.AllowAnyMethod();
builder.AllowAnyHeader();
builder.AllowCredentials();
});
});
}
所以原本的 web.config 的 CORS 設定就可以移除了。
這樣就只要改 appsettings.json ,而且如果有多 Domain 的網頁要存取的話,ASP.NET Core 會依 Request 的來源動態傳回 Access-Control-Allow-Origin 的值。
Enable Cross-Origin Requests (CORS) in ASP.NET Core
preflight request (OPTIONS) WebAPI 時,會回 405 Method Not Allowed ?
.NET Core how to add any origin to CORS and allow credentials