我运行 php artisan make:auth 命令,我将逐步解释之后我做什么来理解场景,
- 登录到新会话 (example.com/home(
- 打开一个新选项卡并粘贴 URL,即 example.com/home。
- 现在,使用同一会话打开了 2 个选项卡。
- 我从其中一个选项卡中单击注销,它工作得很好
- 然后,当我尝试从另一个选项卡注销时,它给了我一个错误,说"419页面已过期",即使重新加载后它也无处可去。
问题是,可能会出现这些情况,我不想看到此错误消息,只需在单击注销后注销,即使会话已过期。
注意:此问题不是因为未添加@csrf
嗯,这是一个明显的消息,你可以尝试为该页面制作更好的布局,但仍然最好显示它,以便用户知道发生了什么。如果您想以不同的方式处理它,您可以尝试重定向到登录页面。
因此,在渲染方法的appExceptionsHandler.php
文件中,添加以下内容:
if ($exception instanceof IlluminateSessionTokenMismatchException) {
return redirect()->route('login');
}
该问题的解决方案相对简单,需要对验证CsrfToken中间件;
use Closure;
public function handle($request, Closure $next)
{
if(!Auth::check() && $request->route()->named('logout')) {
$this->except[] = route('logout');
}
return parent::handle($request, $next);
}
通常,此文件仅包含应从 csrf 忽略的路由$except数组。
在此代码中,我们重写 handle 方法并执行两项检查。
- 用户是访客(即,不使用经过身份验证的会话(,并且,
- 是注销路由的路由
如果两者都为真,那么我们将"注销"添加到 except 数组中。 然后,我们将控制权传递给核心 VerifyCsrfMiddleware,该中间件识别阵列中是否存在注销路由,并绕过检查。表单数据已正确发布,我们使用注销响应重定向。
用户看不到错误页面。
通过以这种方式检查,我们确保CSRF令牌仍然保护真正的注销请求。
太晚(
添加 app/Http/Middleware/VerifyCsrfToken.php
use Closure;
public function handle($request, Closure $next)
{
if($request->route()->named('logout')) {
if (auth()->check()) {
auth()->logout();
}
return redirect('/');
}
return parent::handle($request, $next);
}
我认为这些是最好的解决方案。
我直言,您可以尝试修改app/Http/Middleware/VerifyCsrfToken.php
文件。使用如下所示的内容编辑 $except 属性:
class VerifyCsrfToken extends Middleware
{
protected $except = [
'http://example.com/logout',
];
在 Laravel 6 项目中,我最终修改了VerifyCsrfTokenMiddleware
如您所见,我只是将logout
命名的路由添加到排除列表中。
我覆盖了__construct
函数,因为我们在初始化新变量时无法使用route()
函数
<?php
namespace AppHttpMiddleware;
use IlluminateContractsEncryptionEncrypter;
use IlluminateContractsFoundationApplication;
use IlluminateFoundationHttpMiddlewareVerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var bool
*/
protected $addHttpCookie = true;
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
];
/**
* Create a new middleware instance.
*
* @param IlluminateContractsFoundationApplication $app
* @param IlluminateContractsEncryptionEncrypter $encrypter
* @return void
*/
public function __construct(Application $app, Encrypter $encrypter)
{
parent::__construct($app, $encrypter);
$this->except = [
route('logout')
];
}
}
<a href="{{ route('logout') }}" class="dropdown-item notify-item"="event.preventDefault(); document.getElementById('logout-form').submit();">
<i class="fa fa-power-off"></i> <span>{{ __('Logout') }} </span>
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
@csrf
</form>
您错过了注销表单中的@csrf,因此只有您收到错误 419
您需要将 CSRF 令牌添加到表单中:
<form action="{{ route('logout') }}" method="POST">
@csrf
<button type="submit" class="btn nav-link">Logout</button>
</form>
拉拉维尔 8.x 文档