CSRF 防护

发起请求

Laravel 会在通过 Inertia 或 Axios 发起请求时自动包含正确的 CSRF 令牌。但是,如果您使用的是 Laravel,请确保从您的项目中省略 csrf-token 元标签,因为这会阻止 CSRF 令牌正确刷新。

如果您的服务器端框架包含跨站点请求伪造 (CSRF) 防护,您需要确保每个 Inertia 请求都包含必要的 CSRF 令牌,用于 POSTPUTPATCHDELETE 请求。

当然,正如我们已经讨论过的,一些服务器端框架(如 Laravel)会在发起请求时自动处理 CSRF 令牌的包含。**因此,使用这些框架之一时,不需要额外的配置。**

但是,如果您需要手动处理 CSRF 防护,一种方法是在每个响应中包含 CSRF 令牌作为 prop。然后,您可以在发起 Inertia 请求时使用该令牌。

import { router, usePage } from '@inertiajs/vue3'

const page = usePage()

router.post('/users', {
  _token: page.props.csrf_token,
  name: 'John Doe',
  email: '[email protected]',
})

您甚至可以使用 Inertia 的 共享数据 功能,在每个响应中自动包含 csrf_token

但是,更好的方法是使用 axios 中已内置的 CSRF 功能。Axios 是 Inertia 在幕后使用的 HTTP 库。

Axios 会自动检查 XSRF-TOKEN cookie 是否存在。如果存在,它将在发起任何请求时在 X-XSRF-TOKEN 标头中包含该令牌。

实现此功能的最简单方法是使用服务器端中间件。只需在每个响应中包含 XSRF-TOKEN cookie,然后使用 axios 从请求中发送的 X-XSRF-TOKEN 标头验证该令牌。

处理不匹配

当发生 CSRF 令牌不匹配时,您的服务器端框架可能会抛出一个异常,导致错误响应。例如,使用 Laravel 时,会抛出一个 TokenMismatchException,导致出现 419 错误页面。由于这不是有效的 Inertia 响应,因此错误会显示在模态框中。

显然,这不是很好的用户体验。处理这些错误的更好方法是返回重定向到上一个页面的操作,以及一个指示页面已过期的闪存消息。这将导致一个有效的 Inertia 响应,其中闪存消息作为 prop 可用,然后您可以将其显示给用户。当然,您需要与 Inertia 共享您的 闪存消息,才能使此方法生效。

使用 Laravel 时,您可以修改应用程序的异常处理程序,以自动将用户重定向回他们之前所在的页面,同时向会话闪存一条消息。要实现此目的,您可以在应用程序的 bootstrap/app.php 文件中使用 respond 异常方法。

use Symfony\Component\HttpFoundation\Response;

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->respond(function (Response $response) {
        if ($response->getStatusCode() === 419) {
            return back()->with([
                'message' => 'The page expired, please try again.',
            ]);
        }

        return $response;
    });
});

最终结果是为您的用户提供更好的体验。用户不会看到错误模态框,而是会收到一条消息,指示页面“已过期”,并要求他们重试。