Povolení žádostí mezi zdroji v ASP.NET webovém rozhraní API 2
Tento obsah je pro předchozí verzi rozhraní .NET. Nový vývoj by měl používat ASP.NET Core. Další informace o používání webového rozhraní API a žádostí mezi zdroji (CORS) v ASP.NET Core najdete v tématech:
- Kurz: Vytvoření webového rozhraní API pomocí ASP.NET Core
- Povolit žádosti mezi zdroji (CORS) v ASP.NET Core
Zabezpečení prohlížečů brání webovým stránkám v odesílání požadavků AJAX na jinou doménu. Toto omezení se nazývá zásady stejného původu a brání škodlivému webu v čtení citlivých dat z jiné lokality. V některých případech však můžete chtít povolit jiným webům volat vaše webové rozhraní API.
Sdílení prostředků mezi zdroji (CORS) je standard W3C, který umožňuje serveru zmírnit zásady stejného zdroje. Při použití CORS může server explicitně umožnit některé žádosti o více zdrojů a současně odmítat jiné. CORS je bezpečnější a pružnější než u předchozích technik, jako je JSONP. V tomto kurzu se dozvíte, jak ve vaší aplikaci webového rozhraní API povolit CORS.
Software použitý v tomto kurzu
- Visual Studio
- Webové rozhraní API 2,2
Úvod
Tento kurz ukazuje podporu CORS ve webovém rozhraní API ASP.NET. Začneme vytvořením dvou ASP.NET projektů – One s názvem "WebService", který hostuje kontroler webového rozhraní API a druhý s názvem "webový klient", který volá webovou službu. Vzhledem k tomu, že jsou tyto dvě aplikace hostovány v různých doménách, požadavek AJAX od WebClient na WebService je požadavek na více zdrojů.

Co je "stejný zdroj"?
Dvě adresy URL mají stejný původ, pokud mají totožná schémata, hostitele a porty. (RFC 6454)
Tyto dvě adresy URL mají stejný původ:
http://example.com/foo.htmlhttp://example.com/bar.html
Tyto adresy URL mají jiný původ než předchozí dvě:
http://example.net– Odlišná doménahttp://example.com:9000/foo.html– Jiný porthttps://example.com/foo.html– Odlišné schémahttp://www.example.com/foo.html– Odlišná subdoména
Note
Internet Explorer při porovnávání míst původu nebere v úvahu port.
Vytvoření projektu WebService
Note
V této části se předpokládá, že už máte informace o tom, jak vytvářet projekty webového rozhraní API. Pokud ne, přečtěte si téma Začínáme s webovým rozhraním API ASP.NET.
Spusťte Visual Studio a vytvořte nový projekt webové aplikace v ASP.NET (.NET Framework) .
V dialogovém okně Nová webová aplikace v ASP.NET vyberte šablonu prázdného projektu. V části Přidat složky a základní reference pro vyberte zaškrtávací políčko webové rozhraní API .

Přidejte kontroler Web API s názvem
TestControllers následujícím kódem:using System.Net.Http; using System.Web.Http; namespace WebService.Controllers { public class TestController : ApiController { public HttpResponseMessage Get() { return new HttpResponseMessage() { Content = new StringContent("GET: Test message") }; } public HttpResponseMessage Post() { return new HttpResponseMessage() { Content = new StringContent("POST: Test message") }; } public HttpResponseMessage Put() { return new HttpResponseMessage() { Content = new StringContent("PUT: Test message") }; } } }Aplikaci můžete spustit místně nebo nasadit do Azure. (Pro snímky obrazovky v tomto kurzu se aplikace nasadí do Azure App Service Web Apps.) Chcete-li ověřit, zda webové rozhraní API funguje, přejděte na adresu
http://hostname/api/test/, kde název hostitele je doména, do které jste aplikaci nasadili. Měla by se zobrazit zpráva s textem odpovědi, " Get: test " .
Vytvoření projektu WebClient
Vytvořte další projekt webové aplikace v ASP.NET (.NET Framework) a vyberte šablonu projektu MVC . V případě potřeby vyberte změnit ověřování > bez ověřování. Pro tento kurz nepotřebujete ověřování.

V Průzkumník řešení otevřete zobrazení souborů/domů/index. cshtml. Nahraďte kód v tomto souboru následujícím kódem:
<div> <select id="method"> <option value="get">GET</option> <option value="post">POST</option> <option value="put">PUT</option> </select> <input type="button" value="Try it" onclick="sendRequest()" /> <span id='value1'>(Result)</span> </div> @section scripts { <script> // TODO: Replace with the URL of your WebService app var serviceUrl = 'http://mywebservice/api/test'; function sendRequest() { var method = $('#method').val(); $.ajax({ type: method, url: serviceUrl }).done(function (data) { $('#value1').text(data); }).fail(function (jqXHR, textStatus, errorThrown) { $('#value1').text(jqXHR.responseText || textStatus); }); } </script> }Pro proměnnou serviceUrl použijte identifikátor URI aplikace WebService.
Spusťte aplikaci webového klienta lokálně nebo ji publikujte na jiném webu.
Po kliknutí na tlačítko vyzkoušet se odešle požadavek AJAX do aplikace WebService pomocí metody HTTP uvedené v rozevíracím seznamu (GET, POST nebo PUT). To vám umožní prošetřit různé požadavky na více zdrojů. V současné době aplikace webové služby nepodporuje CORS, takže pokud kliknete na tlačítko, zobrazí se chyba.

Note
Pokud sledujete provoz protokolu HTTP v nástroji jako Fiddler, uvidíte, že prohlížeč odesílá požadavek GET a požadavek je úspěšný, ale volání AJAX vrátí chybu. Je důležité pochopit, že zásady stejného původu nebrání prohlížeči Odeslat požadavek. Místo toho zabrání aplikaci zobrazit odpověď.

Povolení CORS
Teď v aplikaci WebService povolíte CORS. Nejdřív přidejte balíček NuGet CORS. V aplikaci Visual Studio v nabídce nástroje vyberte Správce balíčků NuGet a pak vyberte Konzola správce balíčků. V okně konzoly Správce balíčků zadejte následující příkaz:
Install-Package Microsoft.AspNet.WebApi.Cors
Tento příkaz nainstaluje nejnovější balíček a aktualizuje všechny závislosti, včetně základních knihoven webových rozhraní API. Použijte -Version příznak k zacílení na konkrétní verzi. Balíček CORS vyžaduje webové rozhraní API 2,0 nebo novější.
Otevřete soubor App App _ Start/WebApiConfig. cs. Do metody WebApiConfig. Register přidejte následující kód:
using System.Web.Http;
namespace WebService
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// New code
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
Dále přidejte atribut [EnableCors] do TestController třídy:
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;
namespace WebService.Controllers
{
[EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")]
public class TestController : ApiController
{
// Controller methods not shown...
}
}
Pro parametr původes použijte identifikátor URI, kde jste nasadili aplikaci WebClient. To umožňuje, aby se požadavky na více zdrojů od WebClient a pořád nepovolovaly všechny ostatní požadavky mezi doménami. Později popište parametry pro [EnableCors] podrobněji.
Na konec adresy URL původních míst nepoužívejte lomítko.
Znovu nasaďte aktualizovanou aplikaci WebService. Nemusíte aktualizovat WebClient. Požadavek AJAX z WebClient by teď měl být úspěšný. Metody GET, PUT a POST jsou povoleny.

Jak CORS funguje
Tato část popisuje, co se stane v žádosti CORS, na úrovni zpráv HTTP. Je důležité pochopit, jak CORS funguje, abyste mohli správně nakonfigurovat atribut [EnableCors] a řešit potíže, pokud nefungují podle očekávání.
Specifikace CORS zavádí několik nových hlaviček protokolu HTTP, které umožňují žádosti mezi zdroji. Pokud prohlížeč podporuje CORS, nastavuje tyto hlavičky pro žádosti mezi zdroji automaticky. v kódu JavaScriptu nemusíte nic dělat.
Tady je příklad žádosti o více zdrojů. Hlavička "Origin" poskytuje doménu lokality, která požadavek provádí.
GET http://myservice.azurewebsites.net/api/test HTTP/1.1
Referer: http://myclient.azurewebsites.net/
Accept: */*
Accept-Language: en-US
Origin: http://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
Pokud server tuto žádost povoluje, nastaví hlavičku Access-Control-Allow-Origin. Hodnota této hlavičky odpovídá záhlaví původu, nebo se jedná o zástupnou hodnotu " * ", což znamená, že je povolen libovolný původ.
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
Access-Control-Allow-Origin: http://myclient.azurewebsites.net
Date: Wed, 05 Jun 2013 06:27:30 GMT
Content-Length: 17
GET: Test message
Pokud odpověď nezahrnuje hlavičku Access-Control-Allow-Origin, požadavek AJAX se nezdařil. Konkrétně prohlížeč požadavek nepovoluje. I v případě, že server vrátí úspěšnou odpověď, prohlížeč nezpřístupňuje odpověď klientské aplikaci.
Požadavky na kontrolu před výstupem
V případě některých žádostí CORS pošle prohlížeč další žádost s názvem "žádost o kontrolu před odesláním skutečné žádosti o prostředek".
Prohlížeč může požadavek na předběžné kontroly přeskočit, pokud jsou splněné následující podmínky:
Metoda Request je GET, HEAD nebo POST a
Aplikace nenastavuje žádné hlavičky požadavků , které jsou jiné než akceptující, Accept-Language, Content-Language, Content-Type nebo Last-ID.
Hlavička Content-Type (Pokud je nastavena) je jedna z následujících:
- Application/x-www-form-urlencoded
- multipart/form-data
- Text/prostý
Pravidlo týkající se hlaviček požadavků platí pro hlavičky, které aplikace nastaví pomocí volání setRequestHeader na objektu XMLHttpRequest . (Specifikace CORS volá tyto "hlavičky žádostí o autora".) Pravidlo se nevztahuje na hlavičky, které může prohlížeč nastavit, jako je například uživatelský agent, hostitel nebo délka obsahu.
Tady je příklad žádosti o kontrolu před výstupem:
OPTIONS http://myservice.azurewebsites.net/api/test HTTP/1.1
Accept: */*
Origin: http://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
Požadavek na lety používá metodu HTTP. Obsahuje dvě speciální hlavičky:
- Access-Control-Request-method: metoda HTTP, která bude použita pro skutečný požadavek.
- Access-Control-Request-Headers seznam hlaviček požadavků, které aplikace nastaví na skutečném požadavku. (Znovu nezahrnuje hlavičky, které nastaví prohlížeč.)
Tady je příklad odpovědi za předpokladu, že server povoluje požadavek:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 0
Access-Control-Allow-Origin: http://myclient.azurewebsites.net
Access-Control-Allow-Headers: x-my-custom-header
Access-Control-Allow-Methods: PUT
Date: Wed, 05 Jun 2013 06:33:22 GMT
Odpověď obsahuje hlavičku Access-Control-Allow-Methods, která obsahuje seznam povolených metod, a volitelně hlavičku Access-Control-Allow-Headers, která obsahuje seznam povolených hlaviček. Pokud je žádost o kontrolu předem úspěšná, prohlížeč pošle skutečný požadavek, jak je popsáno výše.
Nástroje běžně používané k testování koncových bodů s požadavky na možnosti kontroly před výstupem (například Fiddler a post) neodesílají ve výchozím nastavení hlavičky požadované možnosti. Potvrďte, Access-Control-Request-Method že Access-Control-Request-Headers jsou hlavičky a odesílány spolu s požadavkem a že hlavičky možností dosáhnou aplikace prostřednictvím služby IIS.
Pokud chcete nakonfigurovat službu IIS tak, aby aplikaci ASP.NET mohla přijímat a zpracovávat žádosti o možnosti, přidejte do souboru web.config aplikace následující konfiguraci v <system.webServer><handlers> části:
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Odebrání OPTIONSVerbHandler brání službě IIS v zpracování požadavků na možnosti. Nahrazení umožňuje, ExtensionlessUrlHandler-Integrated-4.0 aby se možnosti dostaly do aplikace, protože registrace výchozího modulu povoluje pouze požadavky GET, Head, post a Debug s příponami URL bez přípony.
Pravidla oboru pro [EnableCors]
Pro všechny řadiče webového rozhraní API ve vaší aplikaci můžete povolit CORS na akci, pro každý kontroler nebo globálně.
Na akci
Chcete-li povolit CORS pro jednu akci, nastavte v metodě Action atribut [EnableCors] . Následující příklad povoluje CORS GetItem jenom pro metodu.
public class ItemsController : ApiController
{
public HttpResponseMessage GetAll() { ... }
[EnableCors(origins: "http://www.example.com", headers: "*", methods: "*")]
public HttpResponseMessage GetItem(int id) { ... }
public HttpResponseMessage Post() { ... }
public HttpResponseMessage PutItem(int id) { ... }
}
Na kontroler
Pokud jste pro třídu kontroleru nastavili [EnableCors] , vztahuje se na všechny akce na řadiči. Pro zakázání CORS pro akci přidejte k akci atribut [DisableCors] . Následující příklad povoluje CORS pro všechny metody s výjimkou PutItem .
[EnableCors(origins: "http://www.example.com", headers: "*", methods: "*")]
public class ItemsController : ApiController
{
public HttpResponseMessage GetAll() { ... }
public HttpResponseMessage GetItem(int id) { ... }
public HttpResponseMessage Post() { ... }
[DisableCors]
public HttpResponseMessage PutItem(int id) { ... }
}
Univerzál
Pokud chcete povolit CORS pro všechny řadiče webového rozhraní API ve vaší aplikaci, předejte instanci EnableCorsAttribute do metody EnableCors :
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("www.example.com", "*", "*");
config.EnableCors(cors);
// ...
}
}
Pokud nastavíte atribut ve více než jednom oboru, pořadí priorit je:
- Akce
- Controller
- Globální
Nastavení povolených zdrojů
Parametr origines atributu [EnableCors] určuje, které zdroje mají povolený přístup k prostředku. Hodnota je čárkami oddělený seznam povolených zdrojů.
[EnableCors(origins: "http://www.contoso.com,http://www.example.com",
headers: "*", methods: "*")]
Můžete také použít zástupnou hodnotu " * " pro povolení požadavků z libovolného původu.
Před povolením požadavků z libovolného počátku zvažte pečlivou pozornost. To znamená, že každý web může ve webovém rozhraní API vyvolat volání AJAX.
// Allow CORS for all origins. (Caution!)
[EnableCors(origins: "*", headers: "*", methods: "*")]
Nastavení povolených metod HTTP
Parametr metody atributu [EnableCors] určuje, které metody HTTP mají povolen přístup k prostředku. Pro povolení všech metod použijte zástupný znak " * ". Následující příklad povoluje pouze požadavky GET a POST.
[EnableCors(origins: "http://www.example.com", headers: "*", methods: "get,post")]
public class TestController : ApiController
{
public HttpResponseMessage Get() { ... }
public HttpResponseMessage Post() { ... }
public HttpResponseMessage Put() { ... }
}
Nastavení povolených hlaviček žádosti
Tento článek popisuje předchozí způsob, jakým může požadavek na kontrolu před výstupem zahrnovat hlavičku Access-Control-Request-Headers, v níž je uveden seznam hlaviček protokolu HTTP, které aplikace nastavila (záhlaví žádostí s názvem "autor žádosti"). Parametr Headers atributu [EnableCors] určuje, které hlavičky žádostí autora jsou povoleny. Pro povolení všech hlaviček nastavte záhlaví na " * ". Pokud chcete povolit konkrétní záhlaví, nastavte záhlaví na seznam povolených hlaviček oddělených čárkami:
[EnableCors(origins: "http://example.com",
headers: "accept,content-type,origin,x-my-header", methods: "*")]
Nicméně prohlížeče nejsou zcela konzistentní v tom, jak nastavily Access-Control-Request-Headers. Například Chrome aktuálně obsahuje "Origin". FireFox neobsahuje standardní hlavičky, jako je "Accept", ani když ji aplikace nastaví ve skriptu.
Pokud nastavíte záhlaví na jinou hodnotu než " * ", měli byste zahrnout aspoň "přijmout", "Content-Type" a "Origin" a také všechna vlastní záhlaví, která chcete podporovat.
Nastavení povolených hlaviček odpovědí
Ve výchozím nastavení prohlížeč nezveřejňuje všechny hlavičky odpovědí na aplikaci. Ve výchozím nastavení jsou k dispozici následující hlavičky odpovědí:
- Cache-Control
- Obsah – jazyk
- Typ obsahu
- Platnost vyprší
- Last-Modified
- Pragma
Specifikace CORS volá tyto jednoduché hlavičky odpovědi. Pro zpřístupnění dalších hlaviček pro aplikaci nastavte parametr exposedHeaders [EnableCors].
V následujícím příkladu Get Metoda kontroleru nastaví vlastní hlavičku s názvem "X-Custom-header". Ve výchozím nastavení prohlížeč nebude tuto hlavičku vystavovat v žádosti o více zdrojů. Pokud chcete, aby byla hlavička dostupná, zahrňte do exposedHeaders hodnotu "X-Custom-header".
[EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "X-Custom-Header")]
public class TestController : ApiController
{
public HttpResponseMessage Get()
{
var resp = new HttpResponseMessage()
{
Content = new StringContent("GET: Test message")
};
resp.Headers.Add("X-Custom-Header", "hello");
return resp;
}
}
Předávání přihlašovacích údajů v žádostech mezi zdroji
Přihlašovací údaje vyžadují zvláštní zpracování v žádosti CORS. Ve výchozím nastavení prohlížeč neodesílá žádné přihlašovací údaje pomocí žádosti o více zdrojů. Přihlašovací údaje zahrnují soubory cookie i schémata ověřování protokolu HTTP. Aby bylo možné odesílat přihlašovací údaje pomocí žádosti o více zdrojů, musí klient nastavit XMLHttpRequest. withCredentials na hodnotu true.
Přímé použití XMLHttpRequest :
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com/api/test');
xhr.withCredentials = true;
V jQuery:
$.ajax({
type: 'get',
url: 'http://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
Server navíc musí přihlašovací údaje umožňovat. Pokud chcete ve webovém rozhraní API zapnout přihlašovací údaje pro více zdrojů, nastavte vlastnost SupportsCredentials na hodnotu true v atributu [EnableCors] :
[EnableCors(origins: "http://myclient.azurewebsites.net", headers: "*",
methods: "*", SupportsCredentials = true)]
Pokud má tato vlastnost hodnotu true, bude odpověď HTTP zahrnovat hlavičku Access-Control-Allow-Credentials. Tato hlavička obsahuje informace o prohlížeči, který server umožňuje přihlašovací údaje pro požadavek mezi zdroji.
Pokud prohlížeč odesílá přihlašovací údaje, ale odpověď nezahrnuje platné záhlaví Access-Control-Allow-Credentials, prohlížeč nezveřejňuje odpověď na aplikaci a požadavek AJAX selže.
Buďte opatrní při nastavení SupportsCredentials na hodnotu true, protože to znamená, že web v jiné doméně může posílat přihlašovací údaje přihlášeného uživatele k webovému rozhraní API jménem uživatele bez ohledu na uživatele. Specifikace CORS také uvádí, že nastavení původce na " * " je neplatné, pokud má SupportsCredentials hodnotu true.
Vlastní poskytovatelé zásad CORS
Atribut [EnableCors] implementuje rozhraní ICorsPolicyProvider . Můžete poskytnout vlastní implementaci vytvořením třídy, která je odvozena z atributu a implementuje ICorsPolicyProvider.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class MyCorsPolicyAttribute : Attribute, ICorsPolicyProvider
{
private CorsPolicy _policy;
public MyCorsPolicyAttribute()
{
// Create a CORS policy.
_policy = new CorsPolicy
{
AllowAnyMethod = true,
AllowAnyHeader = true
};
// Add allowed origins.
_policy.Origins.Add("http://myclient.azurewebsites.net");
_policy.Origins.Add("http://www.contoso.com");
}
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request)
{
return Task.FromResult(_policy);
}
}
Nyní můžete použít atribut na místo, které byste umístili [EnableCors].
[MyCorsPolicy]
public class TestController : ApiController
{
.. //
Vlastní poskytovatel zásad CORS například mohl přečíst nastavení z konfiguračního souboru.
Jako alternativu k používání atributů můžete zaregistrovat objekt ICorsPolicyProviderFactory , který vytváří objekty ICorsPolicyProvider .
public class CorsPolicyFactory : ICorsPolicyProviderFactory
{
ICorsPolicyProvider _provider = new MyCorsPolicyProvider();
public ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
{
return _provider;
}
}
Chcete-li nastavit ICorsPolicyProviderFactory, zavolejte při spuštění metodu rozšíření SetCorsPolicyProviderFactory následujícím způsobem:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.SetCorsPolicyProviderFactory(new CorsPolicyFactory());
config.EnableCors();
// ...
}
}
Podpora prohlížečů
Balíček Web API CORS je technologie na straně serveru. Prohlížeč uživatele musí také podporovat CORS. Stávající verze všech hlavních prohlížečů naštěstí zahrnují podporu CORS.