Preskočiť na obsah

CORS ​

Aplikácia v prehliadači na inom origine potrebuje CORS hlavičky. ApiPresenter ich pridá ku každej odpovedi a ApiDecider vie odpovedať na preflight OPTIONS požiadavky.

Otvoriť diagram v plnej veľkosti

Namiesto 'auto' použite zoznam originov

'auto' dôveruje hlavičke Referer a povoľuje credentials pre ľubovoľnú stránku. Použite setCorsAllowedOrigins() (pribudlo vo verzii 3.6.0) alebo jeden pevný origin. 'auto' v 3.x funguje ďalej rovnako a vo 4.0 sa plánuje odstrániť (#186, milník 4.0.0).

Access-Control-Allow-Origin ​

Každá odpoveď dostane Access-Control-Allow-Methods: POST, DELETE, PUT, GET, OPTIONS a k tomu jedno z nasledujúceho podľa ApiPresenter::setCorsHeader():

HodnotaPosielané hlavičky
'*' (predvolené)Access-Control-Allow-Origin: *
'https://app.example.com'Access-Control-Allow-Origin: https://app.example.com
'auto'schéma, host a port z hlavičky Referer (každý uvedený port okrem 80 ostane, teda aj :443) a Access-Control-Allow-Credentials: true; bez Referer nič
'off'žiadna Access-Control-Allow-Origin
yaml
services:
	apiPresenter:
		factory: Tomaj\NetteApi\Presenters\ApiPresenter
		setup:
			- setCorsHeader('https://app.example.com')

V PHP môžete namiesto preddefinovaných reťazcov odovzdať enum Presenters\CorsMode: CorsMode::Any ('*'), CorsMode::Auto ('auto') a CorsMode::Off ('off').

Toto je jediná služba apiPresenter zo stránky Začíname: pridajte k nej tieto riadky setup:, alebo dajte blok pod rovnakým názvom do iného konfiguračného súboru a Nette ich zlúči. Druhú službu ApiPresenter neregistrujte; dve skončia chybou „Multiple services of type Tomaj\NetteApi\Presenters\ApiPresenter found“.

Povolené originy ​

Od verzie 3.6.0

Toto je odporúčané nastavenie. Na 3.5.0 namiesto toho použite jeden pevný origin.

setCorsAllowedOrigins(array $origins, bool $allowCredentials = false) porovná hlavičku Origin požiadavky so zoznamom. Keď je nastavený, má prednosť pred setCorsHeader().

yaml
services:
	apiPresenter:
		factory: Tomaj\NetteApi\Presenters\ApiPresenter
		setup:
			- setCorsAllowedOrigins(['https://app.example.com', 'http://localhost:3000'], true)
PožiadavkaPosielané hlavičky
Origin je v zoznameAccess-Control-Allow-Origin s týmto originom, Vary: Origin a Access-Control-Allow-Credentials: true, ak je druhý argument true
iný Origin alebo žiadnyiba Vary: Origin, takže prehliadač odpoveď zablokuje

Porovnanie ignoruje veľkosť písmen a predvolené porty sa vynechajú (https://app.example.com:443 zodpovedá https://app.example.com). Každý origin musí mať tvar scheme://host[:port]: bez cesty, bez lomky na konci, bez * či null a medzinárodné domény v punycode. Čokoľvek iné alebo prázdny zoznam vyhodí InvalidArgumentException.

Pri prechode z 'auto' vypíšte originy, ktoré API naozaj volajú (frontendy a hosty pre lokálny vývoj), a setCorsHeader('auto') nahraďte setCorsAllowedOrigins([...], true). true nechajte, len ak sa spoliehate na cookies alebo withCredentials.

Preflight požiadavky ​

Pred POST s JSON telom alebo hlavičkou Authorization pošle prehliadač OPTIONS na tú istú URL. enableGlobalPreflight() naň odpovie pre každý zaregistrovaný endpoint:

yaml
application:
	mapping:
		Api: Tomaj\NetteApi\Presenters\*Presenter

parameters:
	# where the browser frontend runs
	frontendOrigin: 'http://localhost:5173'

services:
	router: App\RouterFactory::create

	- Tomaj\NetteApi\Output\Configurator\EnvConfigurator
	- Tomaj\NetteApi\Error\DefaultErrorHandler

	apiPresenter:
		factory: Tomaj\NetteApi\Presenters\ApiPresenter
		setup:
			# sent as Access-Control-Allow-Origin on every response.
			# Other values: '*' (the default), 'auto' (the origin of the Referer header,
			# with Access-Control-Allow-Credentials: true) and 'off' (no header)
			- setCorsHeader(%frontendOrigin%)

	apiDecider:
		factory: Tomaj\NetteApi\ApiDecider
		setup:
			- addApi(Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'notes'), App\Api\NoteListHandler(), Tomaj\NetteApi\Authorization\NoAuthorization())
			- addApi(Tomaj\NetteApi\EndpointIdentifier('POST', 1, 'notes'), App\Api\NoteCreateHandler(), Tomaj\NetteApi\Authorization\NoAuthorization())
			# answer OPTIONS for every registered endpoint, so the browser may send
			# the Content-Type and Authorization headers
			- enableGlobalPreflight(
				Tomaj\NetteApi\Handlers\CorsPreflightHandler(headers: [
					Access-Control-Allow-Headers: [Content-Type, Authorization],
					Access-Control-Max-Age: '600'
				])
			)

CorsPreflightHandler pridá hlavičky, ktoré mu dáte, a odpovie 200 s []. Bez argumentov pošle Access-Control-Allow-Headers: Authorization a X-Requested-With. OPTIONS na neznámu URL stále vráti 404.

Časté otázky ​

Je 'auto' bezpečné? ​

Nie pre API, ktoré používajú cookies: ľubovoľná stránka, ktorú prihlásený používateľ navštívi, môže volať API s jeho cookies a čítať odpoveď. Použite pevný origin alebo zoznam povolených originov.

Ako povolím viac originov? ​

Cez setCorsAllowedOrigins(). Na 3.5.0, ktoré zoznam nemá, vyberte jeden origin, alebo použite 'off' a hlavičky pridávajte vo webovom serveri.

Preflight mi vracia 404. Prečo? ​

Zavolajte enableGlobalPreflight() a overte, že existuje endpoint s rovnakou verziou, balíkom a akciou. Príklad CORS testuje oboje.

Potrebujem CORS pre volania server-server? ​

Nie, kontrolujú ho len prehliadače.

Posiela sa CORS hlavička aj pri chybách? ​

Áno, pridáva sa pred všetkým ostatným, takže ju majú aj 401, 404 a 500. Pozrite si Architektúru.

Vydané pod licenciou MIT.