Файл: vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestForgery.php
Строк: 359
<?php
namespace IlluminateFoundationHttpMiddleware;
use Closure;
use IlluminateContractsEncryptionDecryptException;
use IlluminateContractsEncryptionEncrypter;
use IlluminateContractsFoundationApplication;
use IlluminateContractsSupportResponsable;
use IlluminateCookieCookieValuePrefix;
use IlluminateCookieMiddlewareEncryptCookies;
use IlluminateFoundationHttpMiddlewareConcernsExcludesPaths;
use IlluminateHttpExceptionsOriginMismatchException;
use IlluminateSessionTokenMismatchException;
use IlluminateSupportArr;
use IlluminateSupportInteractsWithTime;
use SymfonyComponentHttpFoundationCookie;
class PreventRequestForgery
{
use ExcludesPaths,
InteractsWithTime;
/**
* The application instance.
*
* @var IlluminateContractsFoundationApplication
*/
protected $app;
/**
* The encrypter implementation.
*
* @var IlluminateContractsEncryptionEncrypter
*/
protected $encrypter;
/**
* The URIs that should be excluded.
*
* @var array<int, string>
*/
protected $except = [];
/**
* The globally ignored URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected static $neverVerify = [];
/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var bool
*/
protected $addHttpCookie = true;
/**
* Indicates whether requests from the same site should be allowed.
*
* @var bool
*/
protected static $allowSameSite = false;
/**
* Indicates whether only origin verification should be used.
*
* @var bool
*/
protected static $originOnly = false;
/**
* Create a new middleware instance.
*
* @param IlluminateContractsFoundationApplication $app
* @param IlluminateContractsEncryptionEncrypter $encrypter
*/
public function __construct(Application $app, Encrypter $encrypter)
{
$this->app = $app;
$this->encrypter = $encrypter;
}
/**
* Handle an incoming request.
*
* @param IlluminateHttpRequest $request
* @param Closure $next
* @return mixed
*
* @throws IlluminateSessionTokenMismatchException
* @throws IlluminateHttpExceptionsOriginMismatchException
*/
public function handle($request, Closure $next)
{
if (
$this->isReading($request) ||
$this->runningUnitTests() ||
$this->inExceptArray($request) ||
$this->hasValidOrigin($request) ||
$this->tokensMatch($request)
) {
return tap($next($request), function ($response) use ($request) {
if ($this->shouldAddXsrfTokenCookie()) {
$this->addCookieToResponse($request, $response);
}
});
}
throw new TokenMismatchException('CSRF token mismatch.');
}
/**
* Determine if the HTTP request uses a ‘read’ verb.
*
* @param IlluminateHttpRequest $request
* @return bool
*/
protected function isReading($request)
{
return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
}
/**
* Determine if the application is running unit tests.
*
* @return bool
*/
protected function runningUnitTests()
{
return $this->app->runningInConsole() && $this->app->runningUnitTests();
}
/**
* Determine if the request has a valid origin based on the Sec-Fetch-Site header.
*
* @param IlluminateHttpRequest $request
* @return bool
*
* @throws IlluminateHttpExceptionsOriginMismatchException
*/
protected function hasValidOrigin($request)
{
$secFetchSite = $request->header('Sec-Fetch-Site');
if ($secFetchSite === 'same-origin') {
return true;
}
if ($secFetchSite === 'same-site' && static::$allowSameSite) {
return true;
}
if (static::$originOnly) {
throw new OriginMismatchException('Origin mismatch.');
}
return false;
}
/**
* Determine if the session and input CSRF tokens match.
*
* @param IlluminateHttpRequest $request
* @return bool
*/
protected function tokensMatch($request)
{
$token = $this->getTokenFromRequest($request);
return is_string($request->session()->token()) &&
is_string($token) &&
hash_equals($request->session()->token(), $token);
}
/**
* Get the CSRF token from the request.
*
* @param IlluminateHttpRequest $request
* @return string|null
*/
protected function getTokenFromRequest($request)
{
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
try {
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
} catch (DecryptException) {
$token = '';
}
}
return $token;
}
/**
* Determine if the cookie should be added to the response.
*
* @return bool
*/
public function shouldAddXsrfTokenCookie()
{
if (static::$originOnly) {
return false;
}
return $this->addHttpCookie;
}
/**
* Add the CSRF token to the response cookies.
*
* @param IlluminateHttpRequest $request
* @param SymfonyComponentHttpFoundationResponse $response
* @return SymfonyComponentHttpFoundationResponse
*/
protected function addCookieToResponse($request, $response)
{
$config = config('session');
if ($response instanceof Responsable) {
$response = $response->toResponse($request);
}
$response->headers->setCookie($this->newCookie($request, $config));
return $response;
}
/**
* Create a new "XSRF-TOKEN" cookie that contains the CSRF token.
*
* @param IlluminateHttpRequest $request
* @param array $config
* @return SymfonyComponentHttpFoundationCookie
*/
protected function newCookie($request, $config)
{
return new Cookie(
'XSRF-TOKEN',
$request->session()->token(),
$this->availableAt(60 * $config['lifetime']),
$config['path'],
$config['domain'],
$config['secure'],
false,
false,
$config['same_site'] ?? null,
$config['partitioned'] ?? false
);
}
/**
* Indicate that the given URIs should be excluded from CSRF verification.
*
* @param array|string $uris
* @return void
*/
public static function except($uris)
{
static::$neverVerify = array_values(array_unique(
array_merge(static::$neverVerify, Arr::wrap($uris))
));
}
/**
* Indicate that requests from the same site should be allowed.
*
* @param bool $allow
* @return void
*/
public static function allowSameSite($allow = true)
{
static::$allowSameSite = $allow;
}
/**
* Indicate that only origin verification should be used.
*
* @param bool $originOnly
* @return void
*/
public static function useOriginOnly($originOnly = true)
{
static::$originOnly = $originOnly;
}
/**
* Get the URIs that should be excluded.
*
* @return array
*/
public function getExcludedPaths()
{
return array_merge($this->except, static::$neverVerify);
}
/**
* Determine if the cookie contents should be serialized.
*
* @return bool
*/
public static function serialized()
{
return EncryptCookies::serialized('XSRF-TOKEN');
}
/**
* Flush the state of the middleware.
*
* @return void
*/
public static function flushState()
{
static::$neverVerify = [];
static::$allowSameSite = false;
static::$originOnly = false;
}
}