ibcadmin 发表于 2019-11-8 09:52:03

在 ASP.NET Core 中启用跨域请求(CORS)

<p>本文先容怎样在 ASP.NET Core 的应用程序中启用 CORS。</p>
<p>欣赏器安全可以防止网页向其他域发送哀求,而不是为网页提供服务。 此限定称为<em>相同源计谋</em>。 同一源计谋可防止恶意站点读取另一个站点中的敏感数据。 有时,你大概想要答应其他站点对你的应用举行跨域哀求。 有关详细信息,请参阅<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" data-linktype="external">MOZILLA CORS 一文</a>。</p>
<p><a href="https://www.w3.org/TR/cors/" data-linktype="external">跨源资源共享</a>(CORS):</p>
<ul>
<li>是一种 W3C 标准,可让服务器放宽相同的源计谋。</li>
<li>不是一项安全功能,CORS 放宽 security。 API 不能通过答应 CORS 来更安全。 有关详细信息,请参阅<a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#how-cors" data-linktype="self-bookmark">CORS 的工作</a>原理。</li>
<li>答应服务器明白答应一些跨源哀求,同时拒绝其他哀求。</li>
<li>比早期的技能(如<a href="https://docs.microsoft.com/zh-cn/dotnet/framework/wcf/samples/jsonp" data-linktype="absolute-path">JSONP</a>)更安全且更机动。</li>
</ul>
<p><a href="https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/security/cors/sample" data-linktype="external">查察或下载示例代码</a>(<ahref="https://docs.microsoft.com/zh-cn/aspnet/core/index?view=aspnetcore-3.0#how-to-download-a-sample" data-linktype="relative-path">怎样下载</a>)</p>
<h2 id="same-origin">同一原点</h2>
<p>如果两个 Url 具有相同的方案、主机和端口(<a href="https://tools.ietf.org/html/rfc6454" data-linktype="external">RFC 6454</a>),则它们具有相同的源。</p>
<p>这两个 Url 具有相同的源:</p>
<ul>
<li><code>https://example.com/foo.html</code></li>
<li><code>https://example.com/bar.html</code></li>
</ul>
<p>这些 Url 的劈头差别于前两个 Url:</p>
<ul>
<li><code>https://example.net</code> – 个差别的域</li>
<li><code>https://www.example.com/foo.html</code> – 个差别的子域</li>
<li><code>http://example.com/foo.html</code> – 个差别的方案</li>
<li><code>https://example.com:9000/foo.html</code> – 个差别端口</li>
</ul>
<p>比力泉源时,Internet Explorer 不会思量该端口。</p>
<h2 id="cors-with-named-policy-and-middleware">具有定名计谋和中间件的 CORS</h2>
<p>CORS 中间件处理惩罚跨域哀求。 以下代码通过指定源为整个应用启用 CORS:</p>


public class Startup
{
    public Startup(IConfiguration configuration)
    {
      Configuration = configuration;
    }

    readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddCors(options =>
      {
            options.AddPolicy(MyAllowSpecificOrigins,
            builder =>
            {
                builder.WithOrigins("http://example.com",
                                    "http://www.contoso.com");
            });
      });

      services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
      if (env.IsDevelopment())
      {
            app.UseDeveloperExceptionPage();
      }
      else
      {
            app.UseHsts();
      }

      app.UseCors(MyAllowSpecificOrigins);

      app.UseHttpsRedirection();
      app.UseMvc();
    }
}

<p> </p>
<p>前面的代码:</p>
<ul>
<li>将计谋名称设置为 "_myAllowSpecificOrigins"。 计谋名称为恣意名称。</li>
<li>调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.builder.corsmiddlewareextensions.usecors" data-linktype="external">UseCors</a> 扩展方法,这将启用 CORS。</li>
<li>使用<a href="https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions" data-linktype="absolute-path">lambda 表达式</a>调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.corsservicecollectionextensions.addcors" data-linktype="external">AddCors</a>。 Lambda 采取 @no__t 0 对象。 本文稍后将先容<a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#cors-policy-options" data-linktype="self-bookmark">设置选项</a>,如 <code>WithOrigins</code>。</li>
</ul>
<p>@No__t-0 方法调用将 CORS 服务添加到应用的服务容器:</p>


public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
      options.AddPolicy(MyAllowSpecificOrigins,
      builder =>
      {
            builder.WithOrigins("http://example.com",
                              "http://www.contoso.com");
      });
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

<p> </p>
<p>有关详细信息,请参阅本文档中的<a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#cpo" data-linktype="self-bookmark">CORS 计谋选项</a>。</p>
<p>@No__t-0 方法可以链接方法,如以下代码所示:</p>


public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
      options.AddPolicy(MyAllowSpecificOrigins,
      builder =>
      {
            builder.WithOrigins("http://example.com",
                              "http://www.contoso.com")
                              .AllowAnyHeader()
                              .AllowAnyMethod();
      });
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

<p> </p>
<p>留意: URL不得包罗尾随斜杠(<code>/</code>)。 如果 URL 以 <code>/</code> 制止,比力将返回 <code>false</code>,而且不返回任何标头。</p>

<h3 id="apply-cors-policies-to-all-endpoints">将 CORS 计谋应用到全部闭幕点</h3>
<p>以下代码通过 CORS 中间件将 CORS 计谋应用到全部应用闭幕点:</p>

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // Preceding code ommitted.
    app.UseRouting();

    app.UseCors();

    app.UseEndpoints(endpoints =>
    {
      endpoints.MapControllers();
    });

    // Following code ommited.
}

<p> </p>

<p > 告诫</p>
<p>通过闭幕点路由,CORS 中间件必须设置为在对 @no__t 和 <code>UseEndpoints</code> 的调用之间实行。 设置不正确将导致中间件制止正常运行。</p>


<p>请参阅<a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#ecors" data-linktype="self-bookmark">在 Razor Pages、控制器和操纵方法中启用 cors,</a>以在页面/控制器/操纵级别应用 cors 计谋。</p>
<p>有关测试上述代码的说明,请参阅<a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#test" data-linktype="self-bookmark">测试 CORS</a> 。</p>
<p> </p>

<h2 id="enable-cors-with-endpoint-routing">使用闭幕点路由启用 Cors</h2>
<p>使用闭幕点路由,可以根据每个闭幕点启用 CORS,使用 @no__t 的扩展方法集。</p>

app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo", async context => context.Response.WriteAsync("echo"))
    .RequireCors("policy-name");
});

<p> </p>
<p>同样,也可以为全部控制器启用 CORS:</p>
<codedata-author-content="app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors("policy-name");
});
">app.UseEndpoints(endpoints => { endpoints.MapControllers().RequireCors("policy-name"); });
</code>

<h2 id="enable-cors-with-attributes">使用属性启用 CORS</h2>
<p><ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.enablecorsattribute" data-linktype="external">@No__t-1EnableCors @ no__t</a>属性提供了一种用于全局应用 CORS 的更换方法。 @No__t-0 特性可为选定的闭幕点(而不是全部闭幕点)启用 CORS。</p>
<p>使用 @no__t 指定默认计谋,并 <code></code> 指定计谋。</p>
<p>@No__t-0 特性可应用于:</p>
<ul>
<li>Razor 页 <code>PageModel</code></li>
<li>控制器</li>
<li>控制器操纵方法</li>
</ul>
<p>您可以将差别的计谋应用于控制器/页面模子/操纵,<code></code> 属性。 将 <code></code> 属性应用于控制器/页面模子/操纵方法,并在中间件中启用 CORS 时,将应用这两种计谋。 发起不要联合计谋。 使用同一个应用中的 <code></code> 特性或中间件。</p>
<p>下面的代码将差别的计谋应用于每个方法:</p>


")]

public class WidgetController : ControllerBase
{
    // GET api/values
   
   
    public ActionResult<IEnumerable<string>> Get()
    {
      return new string[] { "green widget", "red widget" };
    }

    // GET api/values/5
          // Default policy.
   
    public ActionResult<string> Get(int id)
    {
      switch (id)
      {
            case 1:
                return "green widget";
            case 2:
                return "red widget";
            default:
                return NotFound();
      }
    }
}

<p> </p>

<codedata-author-content="")]

public class WidgetController : ControllerBase
{
    // GET api/values
   
   
    public ActionResult<IEnumerable<string>> Get()
    {
      return new string[] { "green widget", "red widget" };
    }

    // GET api/values/5
          // Default policy.
   
    public ActionResult<string> Get(int id)
    {
      switch (id)
      {
            case 1:
                return "green widget";
            case 2:
                return "red widget";
            default:
                return NotFound();
      }
    }
}
"></code>
<p>以下代码创建 CORS 默认计谋和名为 <code>"AnotherPolicy"</code> 的计谋:</p>


public class StartupMultiPolicy
{
    public StartupMultiPolicy(IConfiguration configuration)
    {
      Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddCors(options =>
      {
            options.AddDefaultPolicy(
                builder =>
                {
                  
                  builder.WithOrigins("http://example.com",
                                        "http://www.contoso.com");
                });

            options.AddPolicy("AnotherPolicy",
                builder =>
                {
                  builder.WithOrigins("http://www.contoso.com")
                                        .AllowAnyHeader()
                                        .AllowAnyMethod();
                });

      });

      services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
      if (env.IsDevelopment())
      {
            app.UseDeveloperExceptionPage();
      }
      else
      {
            app.UseHsts();
      }

      app.UseHttpsRedirection();
      app.UseMvc();
    }
}

<p> </p>
<h3 id="disable-cors">禁用 CORS</h3>
<p><ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.disablecorsattribute" data-linktype="external">@No__t-1DisableCors @ no__t-2</a>属性对控制器/页模子/操纵禁用 CORS。</p>
<h2 id="cors-policy-options">CORS 计谋选项</h2>
<p>本部分先容可在 CORS 计谋中设置的各种选项:</p>
<ul>
<li><a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#set-the-allowed-origins" data-linktype="self-bookmark">设置答应的泉源</a></li>
<li><a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#set-the-allowed-http-methods" data-linktype="self-bookmark">设置答应的 HTTP 方法</a></li>
<li><a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#set-the-allowed-request-headers" data-linktype="self-bookmark">设置答应的哀求标头</a></li>
<li><a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#set-the-exposed-response-headers" data-linktype="self-bookmark">设置公开的响应标头</a></li>
<li><a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#credentials-in-cross-origin-requests" data-linktype="self-bookmark">跨域哀求中的根据</a></li>
<li><a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#set-the-preflight-expiration-time" data-linktype="self-bookmark">设置预检逾期时间</a></li>
</ul>
<p><code>Startup.ConfigureServices</code> 中调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corsoptions.addpolicy" data-linktype="external">AddPolicy</a>。 对于某些选项,最好先阅读<a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#how-cors" data-linktype="self-bookmark">CORS 怎样工作</a>部分。</p>
<h2 id="set-the-allowed-origins">设置答应的泉源</h2>
<p><ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.allowanyorigin" data-linktype="external">AllowAnyOrigin</a> – 答应全部泉源的 CORS 哀求和任何方案(<code>http</code> 或 <code>https</code>)。 <code>AllowAnyOrigin</code> 不安全,因为<em>任何网站</em>都可以向应用程序发出跨域哀求。</p>


<p > 备注</p>
<p>指定 @no__t 0 和 @no__t 为不安全设置,大概导致跨站点哀求伪造。 使用这两种方法设置应用时,CORS 服务将返回无效的 CORS 响应。</p>


<p><code>AllowAnyOrigin</code> 会影响预检哀求和 @no__t 标头。 有关详细信息,请参阅<a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#preflight-requests" data-linktype="self-bookmark">预检哀求</a>部分。</p>

<p><ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.setisoriginallowedtoallowwildcardsubdomains" data-linktype="external">SetIsOriginAllowedToAllowWildcardSubdomains</a> – 将计谋的 @no__t 设置为在评估是否答应源时答应源与设置的通配符域匹配的函数。</p>


options.AddPolicy("AllowSubdomain",
    builder =>
    {
      builder.WithOrigins("https://*.example.com")
            .SetIsOriginAllowedToAllowWildcardSubdomains();
    });

<p> </p>

<h3 id="set-the-allowed-http-methods">设置答应的 HTTP 方法</h3>
<p><ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.allowanymethod" data-linktype="external">AllowAnyMethod</a>:</p>
<ul>
<li>答应任何 HTTP 方法:</li>
<li>影响预检哀求和 @no__t 0 标头。 有关详细信息,请参阅<a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#preflight-requests" data-linktype="self-bookmark">预检哀求</a>部分。</li>
</ul>
<h3 id="set-the-allowed-request-headers">设置答应的哀求标头</h3>
<p>若要答应在 CORS 哀求中发送特定标头(称为<em>作者哀求标头</em>),请调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.withheaders" data-linktype="external">WithHeaders</a> 并指定答应的标头:</p>


options.AddPolicy("AllowHeaders",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .WithHeaders(HeaderNames.ContentType, "x-custom-header");
    });

<p> </p>

<codedata-author-content="options.AddPolicy("AllowHeaders",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .WithHeaders(HeaderNames.ContentType, "x-custom-header");
    });
"></code>
<p>若要答应全部作者哀求标头,请调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.allowanyheader" data-linktype="external">AllowAnyHeader</a>:</p>


options.AddPolicy("AllowAllHeaders",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .AllowAnyHeader();
    });


<codedata-author-content="options.AddPolicy("AllowAllHeaders",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .AllowAnyHeader();
    });
"></code>
<p>此设置会影响预检哀求和 @no__t 0 标头。 有关详细信息,请参阅<a href="https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-3.0#preflight-requests" data-linktype="self-bookmark">预检哀求</a>部分。</p>

<p>仅当在 <code>Access-Control-Request-Headers</code> 中发送的标头与 <code>WithHeaders</code> 中指定的标头完全匹配时,才可以使用 CORS 中间件计谋与 <code>WithHeaders</code> 指定的特定标头匹配。</p>
<p>比方,思量按如下方式设置的应用:</p>
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
<codedata-author-content="app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
">
</code>
<p>CORS 中间件使用以下哀求标头拒绝预检哀求,因为 <code>WithHeaders</code> 中未列出 <code>Content-Language</code> (<ahref="https://docs.microsoft.com/dotnet/api/microsoft.net.http.headers.headernames.contentlanguage" data-linktype="external">HeaderNames</a>):</p>
<code data-author-content="Access-Control-Request-Headers: Cache-Control, Content-Language
">Access-Control-Request-Headers: Cache-Control, Content-Language
</code>
<p>应用返回<em>200 OK</em>响应,但不会向后发送 CORS 标头。 因此,欣赏器不会实行跨域哀求。</p>

<h3 id="set-the-exposed-response-headers">设置公开的响应标头</h3>
<p>默认环境下,欣赏器不会向应用程序公开全部的响应标头。 有关详细信息,请参阅<a href="https://www.w3.org/TR/cors/#simple-response-header" data-linktype="external">W3C 跨域资源共享(术语):简单的响应标头</a>。</p>
<p>默认环境下可用的响应标头包罗:</p>
<ul>
<li><code>Cache-Control</code></li>
<li><code>Content-Language</code></li>
<li><code>Content-Type</code></li>
<li><code>Expires</code></li>
<li><code>Last-Modified</code></li>
<li><code>Pragma</code></li>
</ul>
<p>CORS 规范将这些标头称为<em>简单的响应标头</em>。 若要使其他标头可用于应用程序,请调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.withexposedheaders" data-linktype="external">WithExposedHeaders</a>:</p>


options.AddPolicy("ExposeResponseHeaders",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .WithExposedHeaders("x-custom-header");
    });

<p> </p>

<codedata-author-content="options.AddPolicy("ExposeResponseHeaders",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .WithExposedHeaders("x-custom-header");
    });
"></code>
<h3 id="credentials-in-cross-origin-requests">跨域哀求中的根据</h3>
<p>根据需要在 CORS 哀求中举行特别处理惩罚。 默认环境下,欣赏器不会使用跨域哀求发送根据。 根据包罗 cookie 和 HTTP 身份验证方案。 若要使用跨域哀求发送根据,客户端必须将 <code>XMLHttpRequest.withCredentials</code> 设置为 <code>true</code>。</p>
<p>直接使用 @no__t:</p>

var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;

<p> </p>
<p>使用 jQuery:</p>

$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
    withCredentials: true
}
});

<p> </p>
<p>使用<a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" data-linktype="external">提取 API</a>:</p>

fetch('https://www.example.com/api/test', {
    credentials: 'include'
});

<p> </p>
<p>服务器必须答应根据。 若要答应跨域根据,请调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.allowcredentials" data-linktype="external">AllowCredentials</a>:</p>


options.AddPolicy("AllowCredentials",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .AllowCredentials();
    });

<p> </p>
<p>HTTP 响应包罗一个 @no__t 0 的标头,该标头关照欣赏器服务器答应跨源哀求的根据。</p>
<p>如果欣赏器发送根据,但响应不包罗有效的 @no__t 0 标头,则欣赏器不会向应用程序公开响应,而且跨源哀求会失败。</p>
<p>答应跨域根据会带来安全风险。 另一个域中的网站可以代表用户将登任命户的根据发送给该应用程序,而无需用户的知识。</p>
<p>CORS 规范还指出,如果 @no__t 标头存在,则将源设置为 <code>"*"</code> (全部源)是无效的。</p>
<h3 id="preflight-requests">预检哀求</h3>
<p>对于某些 CORS 哀求,欣赏器会在发出实际哀求之前发送其他哀求。 此哀求称为<em>预检哀求</em>。 如果满意以下条件,欣赏器可以跳过预检哀求:</p>
<ul>
<li>哀求方法为 GET、HEAD 或 POST。</li>
<li>应用未设置 <code>Accept</code>、<code>Accept-Language</code>、<code>Content-Language</code>、<code>Content-Type</code> 或 @no__t 为的哀求标头。</li>
<li>@No__t 的标头(如果已设置)具有以下值之一:
<ul>
<li><code>application/x-www-form-urlencoded</code></li>
<li><code>multipart/form-data</code></li>
<li><code>text/plain</code></li>
</ul>
</li>
</ul>
<p>为客户端哀求设置的哀求标头上的规则实用于应用通过调用 @no__t @no__t 对象上的的标头。 CORS 规范调用这些标头<em>作者哀求标头</em>。 规则不实用于欣赏器可以设置的标头,如 <code>User-Agent</code>、<code>Host</code> 或 <code>Content-Length</code>。</p>
<p>下面是预检哀求的示例:</p>
<code data-author-content="OPTIONS https://myservice.azurewebsites.net/api/test HTTP/1.1
Accept: */*
Origin: https://myclient.azurewebsites.net
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: accept, x-my-custom-header
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net
Content-Length: 0
">OPTIONS https://myservice.azurewebsites.net/api/test HTTP/1.1
Accept: */*
Origin: https://myclient.azurewebsites.net
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: accept, x-my-custom-header
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net
Content-Length: 0</code>
<p>预航班哀求使用 HTTP OPTIONS 方法。 它包罗两个特别标头:</p>
<ul>
<li><code>Access-Control-Request-Method</code>:将用于实际哀求的 HTTP 方法。</li>
<li><code>Access-Control-Request-Headers</code>:应用在实际哀求上设置的哀求标头的列表。 如前文所述,这不包罗欣赏器设置的标头,如 <code>User-Agent</code>。</li>
</ul>
<p>CORS 预检哀求大概包罗一个 @no__t 0 标头,该标头向服务器指示与实际哀求一起发送的标头。</p>
<p>若要答应特定标头,请调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.withheaders" data-linktype="external">WithHeaders</a>:</p>

options.AddPolicy("AllowHeaders",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .WithHeaders(HeaderNames.ContentType, "x-custom-header");
    });

<p> </p>
<p>若要答应全部作者哀求标头,请调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.allowanyheader" data-linktype="external">AllowAnyHeader</a>:</p>


options.AddPolicy("AllowAllHeaders",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .AllowAnyHeader();
    });

<p> </p>

<p>欣赏器的设置方式并不完全划一 <code>Access-Control-Request-Headers</code>。 如果将标头设置为 @no__t 0 (或使用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicy.allowanyheader" data-linktype="external">AllowAnyHeader</a>)以外的任何内容,则至少应包罗 <code>Accept</code>、<code>Content-Type</code> 和 @no__t,以及要支持的任何自界说标头。</p>
<p>下面是针对预检哀求的示例响应(假定服务器答应该哀求):</p>
<code data-author-content="HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 0
Access-Control-Allow-Origin: https://myclient.azurewebsites.net
Access-Control-Allow-Headers: x-my-custom-header
Access-Control-Allow-Methods: PUT
Date: Wed, 20 May 2015 06:33:22 GMT
">HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 0
Access-Control-Allow-Origin: https://myclient.azurewebsites.net
Access-Control-Allow-Headers: x-my-custom-header
Access-Control-Allow-Methods: PUT
Date: Wed, 20 May 2015 06:33:22 GMT
</code>
<p>响应包罗一个 @no__t 0 标头,该标头列出了答应的方法,还可以选择一个 @no__t 标头,此中列出了答应的标头。 如果预检哀求乐成,则欣赏器发送实际哀求。</p>
<p>如果预检哀求被拒绝,应用将返回<em>200 OK</em>响应,但不会向后发送 CORS 标头。 因此,欣赏器不会实行跨域哀求。</p>
<h3 id="set-the-preflight-expiration-time">设置预检逾期时间</h3>
<p>@No__t 的标头指定可缓存对预检哀求的响应的时间长度。 若要设置此标头,请调用 <ahref="https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.setpreflightmaxage" data-linktype="external">SetPreflightMaxAge</a>:</p>

options.AddPolicy("SetPreflightExpiration",
    builder =>
    {
      builder.WithOrigins("http://example.com")
               .SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
    });

<p> </p>
<h2 id="how-cors-works">CORS 怎样工作</h2>
<p>本部分先容 HTTP 消息级别的<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" data-linktype="external">CORS</a>哀求中发生的环境。</p>
<ul>
<li>CORS不是一种安全功能。 CORS 是一种 W3C 标准,可让服务器放宽相同的源计谋。
<ul>
<li>比方,恶意实行组件大概会对站点使用<ahref="https://docs.microsoft.com/zh-cn/aspnet/core/security/cross-site-scripting?view=aspnetcore-3.0" data-linktype="relative-path">克制跨站点脚本(XSS)</a> ,并对启用了 CORS 的站点实行跨站点哀求,以盗取信息。</li>
</ul>
</li>
<li>API 不能通过答应 CORS 来更安全。
<ul>
<li>它由客户端(欣赏器)来欺压实行 CORS。 服务器实行哀求并返反响应,这是返回错误并克制响应的客户端。 比方,以下任何工具都将体现服务器响应:
<ul>
<li><a href="https://www.telerik.com/fiddler" data-linktype="external">Fiddler</a></li>
<li><a href="https://www.getpostman.com/" data-linktype="external">Postman</a></li>
<li><a href="https://docs.microsoft.com/zh-cn/dotnet/csharp/tutorials/console-webapiclient" data-linktype="absolute-path">.NET HttpClient</a></li>
<li>Web 欣赏器,方法是在所在栏中输入 URL。</li>
</ul>
</li>
</ul>
</li>
<li>这是一种方法,使服务器可以大概答应欣赏器实行跨源<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest" data-linktype="external">XHR</a>或<a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" data-linktype="external">获取 API</a>哀求,否则将被克制。
<ul>
<li>欣赏器(不含 CORS)不能实行跨域哀求。 在 CORS 之前,使用<a href="https://www.w3schools.com/js/js_json_jsonp.asp" data-linktype="external">JSONP</a>来绕过此限定。 JSONP 不使用 XHR,它使用 <code><script></code> 标记吸取响应。 答应跨源加载脚本。</li>
</ul>
</li>
</ul>
<p><a href="https://www.w3.org/TR/cors/" data-linktype="external">CORS 规范</a>先容了几个新的 HTTP 标头,它们启用了跨域哀求。 如果欣赏器支持 CORS,则会自动为跨域哀求设置这些标头。 若要启用 CORS,无需自界说 JavaScript 代码。</p>
<p>下面是一个跨源哀求的示例。 @No__t 0 标头提供发出哀求的站点的域。 @No__t 的标头是必须的,而且必须与主机差别。</p>
<code data-author-content="GET https://myservice.azurewebsites.net/api/test HTTP/1.1
Referer: https://myclient.azurewebsites.net/
Accept: */*
Accept-Language: en-US
Origin: https://myclient.azurewebsites.net
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net
">GET https://myservice.azurewebsites.net/api/test HTTP/1.1
Referer: https://myclient.azurewebsites.net/
Accept: */*
Accept-Language: en-US
Origin: https://myclient.azurewebsites.net
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net
</code>
<p>如果服务器答应该哀求,则会在响应中设置 @no__t 的标头。 此标头的值可以与哀求中的 @no__t 0 标头匹配,也可以是通配符值 <code>"*"</code>,表示答应任何源:</p>
<code data-author-content="HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
Access-Control-Allow-Origin: https://myclient.azurewebsites.net
Date: Wed, 20 May 2015 06:27:30 GMT
Content-Length: 12

Test message
">HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
Access-Control-Allow-Origin: https://myclient.azurewebsites.net
Date: Wed, 20 May 2015 06:27:30 GMT
Content-Length: 12

Test message
</code>
<p>如果响应不包罗 @no__t 的标头,则跨域哀求会失败。 详细而言,欣赏器不答应该哀求。 纵然服务器返回乐成的响应,欣赏器也不会将响应提供给客户端应用程序。</p>
<p> </p>
<h2 id="test-cors">测试 CORS</h2>
<p>测试 CORS:</p>
<ol>
<li><ahref="https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/first-web-api?view=aspnetcore-3.0" data-linktype="relative-path">创建 API 项目</a>。 大概,您也可以<a href="https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/security/cors/sample/Cors" data-linktype="external">下载该示例</a>。</li>
<li>使用本文档中的方法之一启用 CORS。 比方:</li>
</ol>


public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
      app.UseDeveloperExceptionPage();
    }
    else
    {
      app.UseHsts();
    }

    // Shows UseCors with CorsPolicyBuilder.
    app.UseCors(builder =>
    {
      builder.WithOrigins("http://example.com",
                            "http://www.contoso.com",
                            "https://localhost:44375",
                            "https://localhost:5001");
    });

    app.UseHttpsRedirection();
    app.UseMvc();
}

<p> </p>

<codedata-author-content="public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
      app.UseDeveloperExceptionPage();
    }
    else
    {
      app.UseHsts();
    }

    // Shows UseCors with CorsPolicyBuilder.
    app.UseCors(builder =>
    {
      builder.WithOrigins("http://example.com",
                            "http://www.contoso.com",
                            "https://localhost:44375",
                            "https://localhost:5001");
    });

    app.UseHttpsRedirection();
    app.UseMvc();
}
"></code>

<p > 告诫</p>
<p><code>WithOrigins("https://localhost:<port>");</code> 应仅用于测试雷同于<a href="https://github.com/aspnet/AspNetCore.Docs/tree/live/aspnetcore/security/cors/sample/Cors" data-linktype="external">下载示例代码</a>的示例应用。</p>

<ol>
<li>创建 web 应用项目(Razor Pages 或 MVC)。 该示例使用 Razor Pages。 可以在与 API 项目相同的办理方案中创建 web 应用。</li>
<li>将以下突出体现的代码添加到<em>索引 cshtml</em>文件中:</li>
</ol>


@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">CORS Test</h1>
</div>

<div>
    <input type="button" value="Test"
         onclick="requestVal('https://<web app>.azurewebsites.net/api/values')" />
    'result'>
</div>

<script>
    function requestVal(uri) {
      const resultSpan = document.getElementById('result');

      fetch(uri)
            .then(response => response.json())
            .then(data => resultSpan.innerText = data)
            .catch(error => resultSpan.innerText = 'See F12 Console for error');
    }
</script>


<codedata-author-content="@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">CORS Test</h1>
</div>

<div>
    <input type="button" value="Test"
         onclick="requestVal('https://<web app>.azurewebsites.net/api/values')" />
   
</div>

<script>
    function requestVal(uri) {
      const resultSpan = document.getElementById('result');

      fetch(uri)
            .then(response => response.json())
            .then(data => resultSpan.innerText = data)
            .catch(error => resultSpan.innerText = 'See F12 Console for error');
    }
</script>
"></code>
<ol>
<li>
<p>在上面的代码中,将 <code>url: 'https://<web app>.azurewebsites.net/api/values/1',</code> 更换为已摆设应用的 URL。</p>
</li>
<li>
<p>摆设 API 项目。 比方,<ahref="https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/azure-apps/index?view=aspnetcore-3.0" data-linktype="relative-path">摆设到 Azure</a>。</p>
</li>
<li>
<p>从桌面运行 Razor Pages 或 MVC 应用,然后单击 "测试" 按钮。 使用 F12 工具查察错误消息。</p>
</li>
<li>
<p>从 @no__t 中删除 localhost 源,并摆设应用。 大概,使用其他端口运行客户端应用。 比方,在 Visual Studio 中运行。</p>
</li>
<li>
<p>与客户端应用程序举行测试。 CORS 故障返回一个错误,但错误消息不能用于 JavaScript。 使用 F12 工具中的 "控制台" 选项卡查察错误。 根据欣赏器,你会收到雷同于以下内容的错误(在 F12 工具控制台中):</p>
<ul>
<li>
<p>使用 Microsoft Edge:</p>
<p>SEC7120: 源 <code>https://localhost:44375</code> 在 @no__t 上找不到跨源资源的访问控制答应源响应标头中的 <code>https://localhost:44375</code></p>
</li>
<li>
<p>使用 Chrome:</p>
<p>对源 <code>https://localhost:44375</code> <code>https://webapi.azurewebsites.net/api/values/1</code> 的 XMLHttpRequest 的访问已被 CORS 计谋克制:哀求的资源上没有 "访问控制-答应" 标头。</p>
</li>
</ul>
</li>
</ol>
<p>可以使用工具(如<a href="https://www.telerik.com/fiddler" data-linktype="external">Fiddler</a>或<a href="https://www.getpostman.com/" data-linktype="external">Postman</a>)测试启用 CORS 的闭幕点。 使用工具时,@no__t 的标头指定的哀求源必须与吸取哀求的主机差别。 如果哀求不是基于 <code>Origin</code> 标头的值<em>跨</em>域的,则:</p>
<ul>
<li>不需要 CORS 中间件来处理惩罚哀求。</li>
<li>不会在响应中返回 CORS 标头。</li>
</ul>
页: [1]
查看完整版本: 在 ASP.NET Core 中启用跨域请求(CORS)