如何在 Laravel 5.x 中注销过期会话?

Posted

技术标签:

【中文标题】如何在 Laravel 5.x 中注销过期会话?【英文标题】:How to log out of an expired session in Laravel 5.x? 【发布时间】:2017-06-22 12:49:03 【问题描述】:

最新版本的 Laravel(正确地)使用 POST 来注销会话。这样做的原因是 GET/HEAD 应该只用于符合 HTTP 的被动操作。

使用 csrf 令牌发布还可以防止恶意用户/站点将您从会话中注销: https://security.stackexchange.com/questions/62769/must-login-and-logout-action-have-csrf-protection

但是如果会话已经超时,并且用户单击注销(这会触发 POST 到注销路由),则会收到令牌不匹配错误。这是有道理的 - 令牌不匹配,因为会话已过期。

我可以根据请求变量捕获特定的 TokenMismatchException,如果是这样,继续他们愉快的方式(到注销的重定向路径,比如“home”或“/”)。像这样:

public function render($request, Exception $e)

    if ($e instanceof TokenMismatchException && $request->getRequestUri() === '/logout') 
        return redirect('/');
    

    return parent::render($request, $e);

我的问题是:如果我这样做,首先令牌的意义是什么?以及如何在用户会话过期时注销用户,同时保持使用带有 CSRF 令牌的 POST 注销的预期结果?

【问题讨论】:

如果需要保护注销:security.stackexchange.com/questions/62769/… 要回答您的问题,请给我信息,什么样的机制使您的会话超时? @Mkay1 假设任何类型的超时(会话超时、会话被破坏等)。您提供的链接与我的问题中的链接相同 【参考方案1】:

对于 Laravel 5.7,请参阅下面的更新


检查身份验证的中间件应该在检查 CSRF 令牌有效性的中间件之前运行。

这样,当会话过期时,您将永远不会首先进行 CSRF 检查,因为您已经在身份验证中间件中检查了会话过期并重定向到那里的登录页面。

这不会影响有效会话退出的CSRF保护,因为有效会话会通过认证中间件。

默认情况下,Laravel 中间件首先运行 CSRF 检查。但是,应该很容易将它们重新排序以另一种方式工作。


对于 Laravel 5.7:

在 Laravel 5.7 中,Illuminate\Foundation\Http\Kernel 类有一个新字段:

/**
 * The priority-sorted list of middleware.
 *
 * This forces non-global middleware to always be in the given order.
 *
 * @var array
 */
protected $middlewarePriority = [
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \Illuminate\Auth\Middleware\Authenticate::class,
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Auth\Middleware\Authorize::class,
];

出现在此字段中的中间件类始终按照它们出现的顺序运行。该字段的默认设置如上所示。 (Laravel 入门项目对这个列表只有一处更改:\App\Http\Middleware\Authenticate::class 而不是 \Illuminate\Auth\Middleware\Authenticate::class。)

如果您将 CSRF 中间件添加到列表中(身份验证中间件下方的任何位置),则应确保它始终按您想要的顺序运行。

【讨论】:

这实际上很有意义。我使用默认路由进行身份验证,并且所有路由都位于身份验证中间件之外(默认情况下),但确实位于 Web 中间件内。我现在会给他们一个洗牌,如果你是对的,我会带着你的答案回来。很好奇为什么默认行为是注销路由在 auth 中间件之外 这并不是说默认行为是注销路由在 auth 中间件之外。就是认证路由的auth中间件默认是在认证控制器的构造函数中设置的,所以它在中间件的常规列表之后运行。 啊,是的,我从来没有换过控制器级中间件,所以忘记它们的存在吧。我只使用路由级别或路由提供者级别的中间件。对我来说感觉更加一致和可见。 @MosheKatz - 一年后,使用 Laravel 5.7。您能否提供有关如何在 CSRF 检查之前重新排序身份验证检查的任何详细信息?我尝试编辑 Kernel.php 并将 $middlewareGroups 移动到课程的末尾,但这没有任何效果。谢谢! @MosheKatz - 非常感谢您的回复。我尝试在 '\App\Http\Middleware\Authenticate::class' 之后添加 '\App\Http\Middleware\VerifyCsrfToken::class' (我想我正在使用入门项目),但没有注意到行为有任何变化.我还尝试将 VerifyCsrdfToken 移到列表末尾,但没有运气。也许我应该提出一个新问题...

以上是关于如何在 Laravel 5.x 中注销过期会话?的主要内容,如果未能解决你的问题,请参考以下文章

会话过期的 laravel 事件监听器,因为会话过期时没有调用注销事件监听器

Laravel 会话过期事件

修复 laravel 5 会话在刷新或进入另一个页面后过期?

Laravel 5 - 用户在会话生命周期后不注销

如何在 Swift 3 的 UIWebview 中会话过期?

Laravel 身份验证会话超时