Laravel 5.5 Axios POST 导致 419 错误 [英] Laravel 5.5 Axios POST results in 419 error

查看:30
本文介绍了Laravel 5.5 Axios POST 导致 419 错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 Vue 向我的 Laravel API 发出 POST 请求.X-CSRF-TOKEN 标头设置正确(我在发送到服务器的 POST 包中看到了这一点).

I am trying to make a POST-request to my Laravel API from Vue. The X-CSRF-TOKEN header is set correctly (I see this in the POST-package sent to the server).

路由有默认的web-middleware.

The route has the default web-middleware.

请求

Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Connection:keep-alive
Content-Length:2
Content-Type:application/json;charset=UTF-8
Host:api.xxx.local
Origin:http://manager.xxx.local
Referer:http://manager.xxx.local/location/planning/2
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36
X-CSRF-TOKEN:EAf94SFJWBhlcwzxrq7nyygrnRSmZTavrnKYHv5C
X-Requested-With:XMLHttpRequest

回复

Request URL:http://api.xxx.local/locationplanning/deleteentry/15
Request Method:POST
Status Code:419 unknown status
Remote Address:127.0.0.1:80
Referrer Policy:no-referrer-when-downgrade

错误堆栈:

{
    "message": "",
    "exception": "Symfony\Component\HttpKernel\Exception\HttpException",
    "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php",
    "line": 203,
    "trace": [
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php",
            "line": 175,
            "function": "prepareException",
            "class": "Illuminate\Foundation\Exceptions\Handler",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/app/Exceptions/Handler.php",
            "line": 47,
            "function": "render",
            "class": "Illuminate\Foundation\Exceptions\Handler",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 83,
            "function": "render",
            "class": "App\Exceptions\Handler",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 55,
            "function": "handleException",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php",
            "line": 49,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 149,
            "function": "handle",
            "class": "Illuminate\View\Middleware\ShareErrorsFromSession",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\Pipeline\{closure}",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php",
            "line": 63,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 149,
            "function": "handle",
            "class": "Illuminate\Session\Middleware\StartSession",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\Pipeline\{closure}",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php",
            "line": 37,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 149,
            "function": "handle",
            "class": "Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\Pipeline\{closure}",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php",
            "line": 59,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 149,
            "function": "handle",
            "class": "Illuminate\Cookie\Middleware\EncryptCookies",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\Pipeline\{closure}",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/app/Http/Middleware/ForgetDomainParameter.php",
            "line": 30,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 149,
            "function": "handle",
            "class": "App\Http\Middleware\forgetDomainParameter",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\Pipeline\{closure}",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 102,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
            "line": 647,
            "function": "then",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
            "line": 622,
            "function": "runRouteWithinStack",
            "class": "Illuminate\Routing\Router",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
            "line": 588,
            "function": "runRoute",
            "class": "Illuminate\Routing\Router",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
            "line": 577,
            "function": "dispatchToRoute",
            "class": "Illuminate\Routing\Router",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
            "line": 176,
            "function": "dispatch",
            "class": "Illuminate\Routing\Router",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 30,
            "function": "Illuminate\Foundation\Http\{closure}",
            "class": "Illuminate\Foundation\Http\Kernel",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
            "line": 30,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 149,
            "function": "handle",
            "class": "Illuminate\Foundation\Http\Middleware\TransformsRequest",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\Pipeline\{closure}",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
            "line": 30,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 149,
            "function": "handle",
            "class": "Illuminate\Foundation\Http\Middleware\TransformsRequest",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\Pipeline\{closure}",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php",
            "line": 27,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 149,
            "function": "handle",
            "class": "Illuminate\Foundation\Http\Middleware\ValidatePostSize",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\Pipeline\{closure}",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php",
            "line": 46,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 149,
            "function": "handle",
            "class": "Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\Pipeline\{closure}",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 102,
            "function": "Illuminate\Routing\{closure}",
            "class": "Illuminate\Routing\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
            "line": 151,
            "function": "then",
            "class": "Illuminate\Pipeline\Pipeline",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
            "line": 116,
            "function": "sendRequestThroughRouter",
            "class": "Illuminate\Foundation\Http\Kernel",
            "type": "->"
        },
        {
            "file": "/Applications/XAMPP/xamppfiles/htdocs/kitchenradar/server/public/index.php",
            "line": 53,
            "function": "handle",
            "class": "Illuminate\Foundation\Http\Kernel",
            "type": "->"
        }
    ]
}

推荐答案

这里的问题是我们将请求从一个域发送到另一个域.Web 前端域是 manager.xxx.local,而 API 域是 api.xxx.local.

The problem here is that we're sending the request from one domain to another. The web frontend domain is manager.xxx.local while the API domain is api.xxx.local.

这很重要,因为 cookie 受限于它们源自的域.为了安全起见,默认情况下,浏览器不会将 cookie 发送到不同的域.Laravel 将 CSRF 令牌存储在用户的 Web 请求会话中,并发送会话 cookie 到浏览器以维护此会话.

This is important because cookies are constrained to the domain they originate from. For security, the browser will not send cookies to a different domain by default. Laravel stores the CSRF token in the user's session for web requests and sends a session cookie to the browser to maintain this session.

即使 引导程序.js 文件,它与默认的 Laravel 项目一起提供,为通过 axios 的 AJAX 请求添加 CSRF 令牌标头,我们仍然需要一个会话,以便 Laravel 可以将令牌标头与服务器上的值进行比较.

Even though the bootstrap.js file, which ships with a default Laravel project, adds the CSRF token header for AJAX requests through axios, we still need a session so that Laravel can compare the token header to the value on the server.

我们看到 419 HTTP 状态码——通常是 TokenMismatchException 的结果——因为 API 请求没有关联到用户会话(没有会话 cookie),所以 没有 CSRF 令牌状态存在于会话中.因此,Laravel 认为该令牌对于 API 请求无效.

We see the 419 HTTP status code—usually the result of a TokenMismatchException—because the API request is not associated with a user session (no session cookie), so no CSRF token state exists in the session. Because of this, Laravel considers the token invalid for the API request.

我们可以通过几种不同的方式解决这个问题.现代浏览器支持跨源资源共享 (CORS),这在一定程度上允许我们通过 AJAX 在域之间共享 cookie.我们的服务器需要发送 Access-Control-Allow-Credentials 标头:

We can solve this problem a couple of different ways. Modern browsers support Cross-Origin Resource Sharing (CORS) which, in part, allows us to share cookies between domains via AJAX. Our server needs to send the Access-Control-Allow-Credentials header:

Access-Control-Allow-Credentials: true

阅读这篇关于 MDN 的文章了解更多信息.Barry vd 的 Laravel CORS 包.如果我们不想手动配置我们的应用程序或网络服务器,Heuvel 可以帮助设置它.

Read this article on MDN for more information. The Laravel CORS package by Barry vd. Heuvel can help set this up if we don't want to manually configure our application or webserver.

然后,我们可以通过在 XMLHttpRequest 上设置以下属性来配置 AJAX 请求以将 cookie 转发到不同的域:

Then, we can configure AJAX requests to forward cookies to a different domain by setting the following property on the XMLHttpRequest:

xhr.withCredentials = true;

在 axios 中,我们可以根据请求配置 withCredentials:

In axios, we can configure withCredentials per request:

axios.get(url, { withCredentials: true });

...或将其设置为默认值:

...or set it as the default:

axios.defaults.withCredentials = true;

如果我们使用 Vue Resource,我们可以设置一个类似的配置选项:

If we're using Vue Resource, we can set a similar configuration option:

Vue.http.options.credentials = true;

即使我们解决了这些问题,当前的设计仍依赖服务器端会话来维护 CSRF 令牌验证的状态.传统 API 通常是无状态(没有与用户绑定的服务器端会话)并使用某种形式的访问令牌(OAuth、JWT 等)对请求进行身份验证.请注意,CSRF 令牌不是这样的令牌之一.

Even when we fix these issues, the current design relies on server-side sessions to maintain state for the CSRF token validation. Conventional APIs are typically stateless (no server-side session tied to a user) and authenticate requests using some form of access token (OAuth, JWT, etc.). Note that the CSRF token is not one such token.

要获得更强大的 API 框架,请考虑使用 Laravel Passport.我们可以添加 CreateFreshApiToken 中间件它会自动生成一个加密的 JWT 来传递用户 ID 和 CSRF 令牌状态,以便我们可以构建一个无会话 API.

For a more robust API framework, consider using Laravel Passport. We can add the CreateFreshApiToken middleware that automatically generates an encrypted JWT to pass the user ID and CSRF token state so that we can build a sessionless API.

如果我们不想构建完整的 API,例如如果我们的 AJAX 请求只是补充服务器生成的视图,我们可能不想通过为这些请求使用单独的域来使应用程序复杂化.

If we don't want to build a full API, such as if our AJAX requests just supplement the views generated by the server, we may not want to complicate the application by using a separate domain for these requests.

注意事项:

如果我停用它,它会起作用,但我需要身份验证....当我停用它时,Auth::user() 为空.

It works if I deactivate it but I need the Auth.... Auth::user() is null when I deactivate it.

用户是null 不是因为我们停用了CSRF,而是因为我们没有会话开始(会话cookie没有发送到API域).

The user is null not because we deactivated CSRF, but because we don't have a session to begin with (the session cookie wasn't sent to the API domain).

如果我将方法更改为 GET(在路由和 axios 中),则不再有错误

If I change the method to GET (in routes and axios) there is no error anymore

Laravel 不会检查从语义上读取数据(GET、HEAD 和 OPTIONS)的请求的 CSRF 令牌.它仅针对修改数据(POST、PUT、DELETE 等)的请求验证令牌.

Laravel does not check the CSRF token for requests that semantically read data (GET, HEAD, and OPTIONS). It verifies the token only for requests that modify data (POST, PUT, DELETE, etc.).

旁注:记住这一点很重要,因为如果我们没有正确设置路由,攻击者可以伪造一个 GET 请求来修改用户的数据.开发人员通常会犯的错误是使用链接(通常带有 .btn)来发出简单的请求,例如删除记录:

Side note: this is important to remember because an attacker can forge a GET request that modifies a user's data if we don't set up our routes appropriately. Developers commonly make the mistake of using a link (often with .btn) to make a simple request like deleting a record:

<a href="/posts/delete/{id}">Delete Post</a>

恶意站点可以在页面上放置相同的链接,并且该请求在点击时会绕过 CSRF 保护,因为浏览器会发送该链接的 GET 请求.

A malicious site can place the same link on a page and the request will bypass CSRF protection when clicked because the browser sends a GET request for the link.

这篇关于Laravel 5.5 Axios POST 导致 419 错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆