modify cors sample and doc

pull/28503/head
Fiyaz Bin Hasan 2023-02-27 02:38:34 +06:00
parent 45cd3a6001
commit 4ab29c171a
19 changed files with 1105 additions and 50 deletions

View File

@ -11,8 +11,6 @@ uid: security/cors
:::moniker range=">= aspnetcore-7.0"
<!-- Currently an exact duplicate of 6.0, but ready for https://github.com/dotnet/AspNetCore.Docs/issues/28420
-->
By [Rick Anderson](https://twitter.com/RickAndMSFT) and [Kirk Larkin](https://twitter.com/serpent5)
This article shows how to enable CORS in an ASP.NET Core app.
@ -26,9 +24,9 @@ Browser security prevents a web page from making requests to a different domain
* Allows a server to explicitly allow some cross-origin requests while rejecting others.
* Is safer and more flexible than earlier techniques, such as [JSONP](/dotnet/framework/wcf/samples/jsonp).
[View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/6.0sample/Cors/WebAPI) ([how to download](xref:index#how-to-download-a-sample))
[View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/8.0sample/Cors/Web2API) ([how to download](xref:index#how-to-download-a-sample))
## Same origin
## Same origin
Two URLs have the same origin if they have identical schemes, hosts, and ports ([RFC 6454](https://tools.ietf.org/html/rfc6454)).
@ -65,7 +63,7 @@ Each approach is detailed in the following sections.
CORS Middleware handles cross-origin requests. The following code applies a CORS policy to all the app's endpoints with the specified origins:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet&highlight=1,5-13,24)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet&highlight=1,5-13,24)]
The preceding code:
@ -81,13 +79,13 @@ See [Test CORS](#testc6) for instructions on testing code similar to the precedi
The <xref:Microsoft.Extensions.DependencyInjection.MvcCorsMvcCoreBuilderExtensions.AddCors%2A> method call adds CORS services to the app's service container:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet&highlight=5-13)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet&highlight=5-13)]
For more information, see [CORS policy options](#cpo6) in this document.
The <xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder> methods can be chained, as shown in the following code:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet2)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet2)]
Note: The specified URL must **not** contain a trailing slash (`/`). If the URL terminates with `/`, the comparison returns `false` and no header is returned.
@ -103,7 +101,7 @@ Typically, `UseStaticFiles` is called before `UseCors`. Apps that use JavaScript
The following highlighted code enables the default CORS policy:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet3&highlight=5,21)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet3&highlight=5,21)]
The preceding code applies the default CORS policy to all controller endpoints.
@ -111,11 +109,9 @@ The preceding code applies the default CORS policy to all controller endpoints.
## Enable Cors with endpoint routing
Enabling CORS on a per-endpoint basis using `RequireCors` ***does not support [automatic preflight requests](#apf).*** For more information, see [this GitHub issue](https://github.com/dotnet/aspnetcore/issues/20709) and [Test CORS with endpoint routing and [HttpOptions]](#tcer).
With endpoint routing, CORS can be enabled on a per-endpoint basis using the <xref:Microsoft.AspNetCore.Builder.CorsEndpointConventionBuilderExtensions.RequireCors%2A> set of extension methods:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_endp&highlight=1,5-13,24,32,35,38)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_endp&highlight=1,5-13,24,32,35,38)]
In the preceding code:
@ -148,11 +144,11 @@ Different policies can be applied to controllers, page models, or action methods
The following code applies a different policy to each method:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Controllers/WidgetController.cs?name=snippet&highlight=6,14)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Controllers/WidgetController.cs?name=snippet&highlight=6,14)]
The following code creates two CORS policies:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_attr)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_attr)]
For the finest control of limiting CORS requests:
@ -172,11 +168,11 @@ The [[DisableCors]](xref:Microsoft.AspNetCore.Cors.DisableCorsAttribute) attribu
The following code defines the CORS policy `"MyPolicy"`:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_dcors)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_dcors)]
The following code disables CORS for the `GetValues2` action:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Controllers/ValuesController.cs?name=snippet&highlight=1,23)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Controllers/ValuesController.cs?name=snippet&highlight=1,23)]
The preceding code:
@ -213,7 +209,7 @@ This section describes the various options that can be set in a CORS policy:
<xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.SetIsOriginAllowedToAllowWildcardSubdomains%2A>: Sets the <xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicy.IsOriginAllowed%2A> property of the policy to be a function that allows origins to match a configured wildcard domain when evaluating if the origin is allowed.
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_aa)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_aa)]
### Set the allowed HTTP methods
@ -226,11 +222,11 @@ This section describes the various options that can be set in a CORS policy:
To allow specific headers to be sent in a CORS request, called [author request headers](https://xhr.spec.whatwg.org/#request), call <xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithHeaders%2A> and specify the allowed headers:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_sa)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_sa)]
To allow all [author request headers](https://www.w3.org/TR/cors/#author-request-headers), call <xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyHeader%2A>:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_aah)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_aah)]
`AllowAnyHeader` affects preflight requests and the [Access-Control-Request-Headers](https://developer.mozilla.org/docs/Web/HTTP/Headers/Access-Control-Request-Method) header. For more information, see the [Preflight requests](#preflight-requests) section.
@ -265,7 +261,7 @@ The response headers that are available by default are:
The CORS specification calls these headers *simple response headers*. To make other headers available to the app, call <xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithExposedHeaders%2A>:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_erh)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_erh)]
### Credentials in cross-origin requests
@ -301,7 +297,7 @@ fetch('https://www.example.com/api/test', {
The server must allow the credentials. To allow cross-origin credentials, call <xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowCredentials%2A>:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_cco)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_cco)]
The HTTP response includes an `Access-Control-Allow-Credentials` header, which tells the browser that the server allows credentials for a cross-origin request.
@ -372,11 +368,11 @@ Using the F12 tools, the console app shows an error similar to one of the follow
To allow specific headers, call <xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithHeaders%2A>:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_whx)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_whx)]
To allow all [author request headers](https://www.w3.org/TR/cors/#author-request-headers), call <xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyHeader%2A>:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_aah2)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_aah2)]
Browsers aren't consistent in how they set `Access-Control-Request-Headers`. If either:
@ -395,19 +391,17 @@ When the CORS policy is applied either:
ASP.NET Core responds to the preflight OPTIONS request.
Enabling CORS on a per-endpoint basis using `RequireCors` currently does **not** support automatic preflight requests.
The [Test CORS](#testc6) section of this document demonstrates this behavior.
<a name="pro6"></a>
### [HttpOptions] attribute for preflight requests
When CORS is enabled with the appropriate policy, ASP.NET Core generally responds to CORS preflight requests automatically. In some scenarios, this may not be the case. For example, using [CORS with endpoint routing](#ecors6).
When CORS is enabled with the appropriate policy, ASP.NET Core generally responds to CORS preflight requests automatically.
The following code uses the [[HttpOptions]](xref:Microsoft.AspNetCore.Mvc.HttpOptionsAttribute) attribute to create endpoints for OPTIONS requests:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Controllers/TodoItems2Controller.cs?name=snippet&highlight=5-17)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Controllers/TodoItems2Controller.cs?name=snippet&highlight=5-17)]
See [Test CORS with endpoint routing and [HttpOptions]](#tcer) for instructions on testing the preceding code.
@ -415,7 +409,7 @@ See [Test CORS with endpoint routing and [HttpOptions]](#tcer) for instructions
The `Access-Control-Max-Age` header specifies how long the response to the preflight request can be cached. To set this header, call <xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.SetPreflightMaxAge%2A>:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Program.cs?name=snippet_pfx)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Program.cs?name=snippet_pfx)]
<a name="how-cors"></a>
@ -436,7 +430,7 @@ This section describes what happens in a [CORS](https://developer.mozilla.org/do
The [CORS specification](https://www.w3.org/TR/cors/) introduced several new HTTP headers that enable cross-origin requests. If a browser supports CORS, it sets these headers automatically for cross-origin requests. Custom JavaScript code isn't required to enable CORS.
The [PUT test button](https://cors3.azurewebsites.net/test) on the deployed [sample](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/3.1sample/Cors/WebAPI)
The [PUT test button](https://cors3.azurewebsites.net/test) on the deployed [sample](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/8.0sample/Cors/Web2API)
The following is an example of a cross-origin request from the [Values](https://cors3.azurewebsites.net/) test button to `https://cors1.azurewebsites.net/api/values`. The `Origin` header:
@ -479,7 +473,7 @@ Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...
```
In `OPTIONS` requests, the server sets the **Response headers** `Access-Control-Allow-Origin: {allowed origin}` header in the response. For example, the deployed [sample](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/3.1sample/Cors/WebAPI), [Delete [EnableCors]](https://cors1.azurewebsites.net/test?number=2) button `OPTIONS` request contains the following headers:
In `OPTIONS` requests, the server sets the **Response headers** `Access-Control-Allow-Origin: {allowed origin}` header in the response. For example, the deployed [sample](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/8.0sample/Cors/Web2API), [Delete [EnableCors]](https://cors1.azurewebsites.net/test?number=2) button `OPTIONS` request contains the following headers:
**General headers**
@ -535,16 +529,6 @@ API projects can reject HTTP requests rather than use `UseHttpsRedirection` to r
<a name="options"></a>
### Display OPTIONS requests
By default, the Chrome and Edge browsers don't show OPTIONS requests on the network tab of the F12 tools. To display OPTIONS requests in these browsers:
* `chrome://flags/#out-of-blink-cors` or `edge://flags/#out-of-blink-cors`
* disable the flag.
* restart.
Firefox shows OPTIONS requests by default.
## CORS in IIS
When deploying to IIS, CORS has to run before Windows Authentication if the server isn't configured to allow anonymous access. To support this scenario, the [IIS CORS module](https://www.iis.net/downloads/microsoft/iis-cors-module)
@ -554,16 +538,16 @@ needs to be installed and configured for the app.
## Test CORS
The [sample download](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/3.1sample/Cors/WebAPI) has code to test CORS. See [how to download](xref:index#how-to-download-a-sample). The sample is an API project with Razor Pages added:
The [sample download](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/8.0sample/Cors/Web2API) has code to test CORS. See [how to download](xref:index#how-to-download-a-sample). The sample is an API project with Razor Pages added:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/ProgramTest.cs?name=snippet_test)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/ProgramTest.cs?name=snippet_test)]
> [!WARNING]
> `WithOrigins("https://localhost:<port>");` should only be used for testing a sample app similar to the [download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/live/aspnetcore/security/cors/3.1sample/Cors).
> `WithOrigins("https://localhost:<port>");` should only be used for testing a sample app similar to the [download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/live/aspnetcore/security/cors/8.0sample/Cors).
The following `ValuesController` provides the endpoints for testing:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Controllers/ValuesController.cs?name=snippet)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Controllers/ValuesController.cs?name=snippet)]
[MyDisplayRouteInfo](https://github.com/Rick-Anderson/RouteInfo/blob/master/Microsoft.Docs.Samples.RouteInfo/ControllerContextExtensions.cs) is provided by the [Rick.Docs.Samples.RouteInfo](https://www.nuget.org/packages/Rick.Docs.Samples.RouteInfo) NuGet package and displays route information.
@ -600,19 +584,21 @@ zz
<a name="tcer"></a>
### Test CORS with endpoint routing and [HttpOptions]
### Test CORS with [EnableCors] attribute and RequireCors method
Enabling CORS on a per-endpoint basis using `RequireCors` currently does **not** support [automatic preflight requests](#apf). Consider the following code which uses [endpoint routing to enable CORS](#ecors6):
Consider the following code which uses [endpoint routing](#ecors6) to enable CORS on a per-endpoint basis using `RequireCors`:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/ProgramTest.cs?name=snippet_teste)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/ProgramTest.cs?name=snippet_teste)]
Notice that only the `/echo` endpoint is using the `RequireCors` to allow cross-origin requests using the specified policy. The controllers below enable CORS using [EnableCors] attribute.
The following `TodoItems1Controller` provides endpoints for testing:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Controllers/TodoItems1Controller.cs?name=snippet2)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Controllers/TodoItems1Controller.cs?name=snippet2)]
Test the preceding code from the [test page](https://cors1.azurewebsites.net/test?number=1) of the deployed [sample](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/3.1sample/Cors/WebAPI).
Test the preceding code from the [test page](https://cors1.azurewebsites.net/test?number=1) of the deployed [sample](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/8.0sample/Cors/Web2API).
The **Delete [EnableCors]** and **GET [EnableCors]** buttons succeed, because the endpoints have `[EnableCors]` and respond to preflight requests. The other endpoints fails. The **GET** button fails, because the [JavaScript](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/3.1sample/Cors/WebAPI/wwwroot/js/MyJS.js) sends:
The **Delete [EnableCors]** and **GET [EnableCors]** buttons succeed, because the endpoints have `[EnableCors]` and respond to preflight requests. The other endpoints fails. The **GET** button fails, because the [JavaScript](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/cors/8.0sample/Cors/Web2API/wwwroot/js/MyJS.js) sends:
```javascript
headers: {
@ -622,7 +608,7 @@ The **Delete [EnableCors]** and **GET [EnableCors]** buttons succeed, because th
The following `TodoItems2Controller` provides similar endpoints, but includes explicit code to respond to OPTIONS requests:
[!code-csharp[](cors/6.0sample/Cors/WebAPI/Controllers/TodoItems2Controller.cs?name=snippet2)]
[!code-csharp[](cors/8.0sample/Cors/Web2API/Controllers/TodoItems2Controller.cs?name=snippet2)]
Test the preceding code from the [test page](https://cors1.azurewebsites.net/test?number=2) of the deployed sample. In the **Controller** drop down list, select **Preflight** and then **Set Controller**. All the CORS calls to the `TodoItems2Controller` endpoints succeed.

View File

@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Docs.Samples;
namespace Web2API.Controllers;
#region snippet2
[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
// PUT: api/TodoItems1/5
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id) {
if (id < 1) {
return Content($"ID = {id}");
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// Delete: api/TodoItems1/5
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/TodoItems1
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")]
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
// Delete: api/TodoItems1/MyDelete2/5
[EnableCors("MyPolicy")]
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
#endregion

View File

@ -0,0 +1,60 @@
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Docs.Samples;
// Used in both the MD file and the RP Test.cshtml
namespace Web2API.Controllers;
#region snippet2
#region snippet
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
#endregion
// [EnableCors] // Not needed as OPTIONS path provided
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
[EnableCors("MyPolicy")] // Rquired for this path
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")] // Rquired for this path
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
#endregion

View File

@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Mvc;
namespace Web2API.Controllers;
#region snippet
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
// PUT: api/TodoItems/5
[HttpPut("{id}")]
public ContentResult PutTodoItem(int id)
{
if (id < 1)
{
return Content($"ID = {id}");
}
return Content($"PutTodoItem: ID = {id}");
}
// Delete: api/TodoItems/5
[HttpDelete("{id}")]
public ContentResult MyDelete(int id)
{
return Content($"MyDelete: ID = {id}");
}
#endregion
// GET: api/TodoItems
[HttpGet]
public ContentResult GetTodoItems()
{
return Content("Get TO DO ");
}
}

View File

@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Docs.Samples;
namespace Web2API.Controllers;
#region snippet
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
#endregion

View File

@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
namespace Web2API.Controllers;
#region snippet
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
// GET api/values
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
#region snippet2
// GET api/values/5
[EnableCors("Policy1")]
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return id switch
{
1 => "green widget",
2 => "red widget",
_ => NotFound(),
};
}
#endregion
}
#endregion

View File

@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Configuration;
namespace WebAPI
{
public class HostPageModel : PageModel
{
public string Host { get; set; }
public void SetHost(IConfiguration configuration, bool changeOrder=false)
{
var h1 = "host1";
var h3 = "host3";
if (changeOrder == true)
{
h1 = "host3";
h3 = "host1";
}
Host = configuration[h1];
var theHost = HttpContext.Request.Host.Value;
if (Host.Contains(theHost))
{
Host = configuration[h3];
}
}
}
}

View File

@ -0,0 +1,45 @@
@page
@model WebAPI.IndexModel
@inject Microsoft.Extensions.Configuration.IConfiguration Configuration
<div class="text-center">
<h1 class="display-4">CORS Test 1</h1>
@{
var host3 = Configuration["host3"];
var theHost = HttpContext.Request.Host.Value;
if (!host3.Contains(theHost) && !theHost.Contains("localhost"))
{
<text>Test from <a href="@host3">@host3</a> or
<a href="https://localhost:5001">https://localhost:5001</a>
</text>
}
}
</div>
<div>
<span id='result'></span>
</div>
<ul>
<li>
<input type="button" value="Values"
onclick="MyTestCors3( '@Model.Host','/api/values', 'GET')" />
</li>
<li>
<input type="button" value="PUT test"
onclick="MyTestCors3( '@Model.Host', '/api/values/5', 'PUT')" />
</li>
<li>
<input type="button" value="GetValues2 [DisableCors]"
onclick="MyTestCors3( '@Model.Host','/api/values/GetValues2', 'GET')" />
</li>
</ul>
<script src="~/js/MyJS.js"></script>

View File

@ -0,0 +1,19 @@
using Microsoft.Extensions.Configuration;
namespace WebAPI
{
public class IndexModel : HostPageModel
{
private readonly IConfiguration Configuration;
public IndexModel(IConfiguration configuration)
{
Configuration = configuration;
}
public void OnGet()
{
SetHost(Configuration);
}
}
}

View File

@ -0,0 +1,79 @@
@page
@using WebAPI
@model TestModel
@inject Microsoft.Extensions.Configuration.IConfiguration Configuration
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@*Must be used with StartupEndPointBugTest*@
<script src="~/js/MyJS.js"></script>
<div class="text-center">
<h1 class="display-4">CORS Test 2</h1>
@{
var host1 = Configuration["host1"];
var hostTest = host1 + "/test";
var theHost = HttpContext.Request.Host.Value;
if (!host1.Contains(theHost) && !theHost.Contains("localhost"))
{
<text>Test from <a href="@hostTest">@hostTest</a> or
<a href="https://localhost:5001/test">https://localhost:5001/test</a>
</text>
}
}
</div>
<div>
<span id='result'></span>
</div>
<form>
<p>
<select asp-for="Number" asp-items="Model.Genres">
</select>
<input type="submit" value="Set Controller" />
</p>
</form>
<ul>
<li>
<input type="button" value="Echo test "
onclick="MyTestCors3( '@Model.Host', '/', 'GET', false)" />
</li>
<li>
<input type="button" value="PUT test "
onclick="MyTestCors3( '@Model.Host', '/api/TodoItems' + '@Model.Number' + '/5', 'PUT', true)" />
</li>
<li>
<input type="button" value="Delete test"
onclick="MyTestCors3( '@Model.Host', '/api/TodoItems' + '@Model.Number' + '/5', 'DELETE', true)" />
</li>
<li>
<input type="button" value="Delete [EnableCors]"
onclick="MyTestCors3( '@Model.Host', '/api/TodoItems' + '@Model.Number' + '/MyDelete2/5', 'DELETE', true)" />
</li>
<li>
@*GET requires preflight request because of
"Content-Type": "x-custom-header"*@
<input type="button" value="GET"
onclick="MyTestCors3( '@Model.Host', '/api/TodoItems' + '@Model.Number', 'GET', true)" />
</li>
<li>
<input type="button" value="GET [EnableCors]"
onclick="MyTestCors3( '@Model.Host', '/api/TodoItems' + '@Model.Number' + '/GetTodoItems2', 'GET', true)" />
</li>
</ul>

View File

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
namespace WebAPI
{
public class TestModel : HostPageModel
{
private readonly IConfiguration Configuration;
public SelectList Genres { get; set; }
[BindProperty(SupportsGet = true)]
public int Number { get; set; } = 1;
public TestModel(IConfiguration configuration)
{
Configuration = configuration;
}
//[BindProperty(SupportsGet = true)]
//public int Number { get; set; } = 1;
public void OnGet()
{
var list = new List<string>() { "1", "2" };
Genres = new SelectList(list);
var dictionary = new Dictionary<int, string>()
{
{1,"No preflight" },
{2,"Preflight" }
};
Genres = new SelectList(dictionary, "Key", "Value");
SetHost(Configuration, true);
}
}
}

View File

@ -0,0 +1,499 @@
#define TESTE // FIRST SECOND THIRD ENDP ATTR DC DCORS AA SA AAH ERH CCO WHX AAH AAH2 PFX
// PFX TEST TESTE
#if FIRST
#region snippet
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
#endregion
#elif SECOND
#region snippet2
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
#endregion
#elif THIRD
#region snippet3
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#endregion
#elif ENDP
#region snippet_endp
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapGet("/echo2",
context => context.Response.WriteAsync("echo2"));
endpoints.MapRazorPages();
});
app.Run();
#endregion
#elif ATTR
#region snippet_attr
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("Policy1",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("AnotherPolicy",
policy =>
{
policy.WithOrigins("http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#endregion
#elif DC
#region snippet_dc
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
#endregion
#elif DCORS
#region snippet_dcors
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
#endregion
#elif AA
#region snippet_aa
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
});
builder.Services.AddControllers();
var app = builder.Build();
#endregion
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#elif SA
#region snippet_sa
using Microsoft.Net.Http.Headers;
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
#endregion
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#elif AAH
#region snippet_aah
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
#endregion
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#elif ERH
#region snippet_erh
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
#endregion
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#elif CCO
#region snippet_cco
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
});
builder.Services.AddControllers();
var app = builder.Build();
#endregion
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#elif WHX
#region snippet_whx
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
#endregion
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#elif AAH2
#region snippet_aah2
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
#endregion
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#elif PFX
#region snippet_pfx
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
});
builder.Services.AddControllers();
var app = builder.Build();
#endregion
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
#endif

View File

@ -0,0 +1,84 @@
#define TEST // TEST TESTE
#if TEST
// Deploy to CORS1
#region snippet_test
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
#endregion
#elif TESTE // Deploy to CORS3
#region snippet_teste
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors("MyPolicy");
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
#endregion
#endif

View File

@ -0,0 +1,14 @@
using System;
namespace WebAPI;
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Rick.Docs.Samples.RouteInfo" Version="1.0.0.4" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@ -0,0 +1,12 @@
{
"host1": "https://cors1.azurewebsites.net",
"host3": "https://cors3.azurewebsites.net",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,20 @@
function MyTestCors3(host, uri, methodName, includeHeaders=false) {
const resultSpan = document.getElementById('result');
const myHeaders = includeHeaders ? { 'Content-Type': 'x-custom-header' } : {};
fetch(`${host}${uri}`, {
method: methodName,
headers: myHeaders,
})
.then(response => {
if (response.ok) {
response.text().then(text => {
resultSpan.innerText = text;
});
}
else {
resultSpan.innerText = response.status;
}
})
.catch(() => resultSpan.innerText = 'See F12 Console for error');
}