Laravel8.40 DELETE请求报错:CSRF token mismatch
问题如题:
第一次用Laravel框架 composer 安装的最新版8.40
各种地方搜了一遍,无解.
情况是这样的:
在中间件VerifyCsrfToken.php 中$except中设置不验证CSRF的路由路径, POST 请求可以正常不验证. DELETE请求还是会验证并报错(后来自己验证PUT也不行)
同一个路由路径如果用DELETE请求, postman就会返回 “message”: “CSRF token mismatch.”,错误
(路由设置的是Route::delete()方法)
现因同一个路由路径需要根据请求方法不同执行不同控制器,DELETE请求必须用,
所以现在暂时是 Kernel.php 中直接注掉了VerifyCsrfToken.php,
这种情况下 delete请求可以不验证CSRF
看了下中间件源码好像也没看到DELETE/PUT相关的内容.
贴上中间件源码,isReading()方法中也只提到 ‘HEAD’, ‘GET’, ‘OPTIONS’可以无视CSRF验证
class VerifyCsrfToken
{
use InteractsWithTime;
/**
* The application instance.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* The encrypter implementation.
*
* @var \Illuminate\Contracts\Encryption\Encrypter
*/
protected $encrypter;
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [];
/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var bool
*/
protected $addHttpCookie = true;
/**
* Create a new middleware instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
* @return void
*/
public function __construct(Application $app, Encrypter $encrypter)
{
$this->app = $app;
$this->encrypter = $encrypter;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*
* @throws \Illuminate\Session\TokenMismatchException
*/
public function handle($request, Closure $next)
{
if (
$this->isReading($request) ||
$this->runningUnitTests() ||
$this->inExceptArray($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 \Illuminate\Http\Request $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 URI that should pass through CSRF verification.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function inExceptArray($request)
{
foreach ($this->except as $except) {
if ($except !== '/') {
$except = trim($except, '/');
}
if ($request->fullUrlIs($except) || $request->is($except)) {
return true;
}
}
return false;
}
/**
* Determine if the session and input CSRF tokens match.
*
* @param \Illuminate\Http\Request $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 \Illuminate\Http\Request $request
* @return string
*/
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 $e) {
$token = '';
}
}
return $token;
}
/**
* Determine if the cookie should be added to the response.
*
* @return bool
*/
public function shouldAddXsrfTokenCookie()
{
return $this->addHttpCookie;
}
/**
* Add the CSRF token to the response cookies.
*
* @param \Illuminate\Http\Request $request
* @param \Symfony\Component\HttpFoundation\Response $response
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function addCookieToResponse($request, $response)
{
$config = config('session');
if ($response instanceof Responsable) {
$response = $response->toResponse($request);
}
$response->headers->setCookie(
new Cookie(
'XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']),
$config['path'], $config['domain'], $config['secure'], false, false, $config['same_site'] ?? null
)
);
return $response;
}
/**
* Determine if the cookie contents should be serialized.
*
* @return bool
*/
public static function serialized()
{
return EncryptCookies::serialized('XSRF-TOKEN');
}
}
本以为VerifyCsrfToken中间件只针对post请求,
没搞懂为什么DELETE和PUT也会被验证,或者说同样设置了$except,
post可以不验证 delete/put就不行
希望有经验的大神解答原理..
推荐文章: