我试图在服务器端的会话中保存客户购物车。客户不需要登录。所以没有Laravel Sanctum或Passport等。Laravel和Vue运行在不同的服务器上(后端:localhost:8000和前端:localhost:9000)。
这里是我的api.php路线。Route::get('get-token', function (Request $request) {
return [
'_token' => $request->session()->token()
];
})->middleware('web');
Route::group(['prefix'=>'v1'], function() {
Route::resource('cart', AppHttpControllersApiV1CartController::class)->middleware('web');
Route::resource('products', AppHttpControllersApiV1ProductController::class);
}
GET/cart请求通过axios和insomnia都可以正常工作:
这里是corospond CartController函数索引:
function index() {
return request()->session()->get('cart');
}
现在的问题是
但是通过axios的POST请求被拒绝,因为419 CSRF令牌不匹配。
奇怪的是,我可以通过失眠发出POST请求。首先从服务器请求令牌,然后在POST请求的主体中指定_token。
> POST /api/v1/cart HTTP/1.1
> Host: localhost:8000
> User-Agent: insomnia/2021.5.3
> Cookie: laravel_session=ZzbpJsfvV22NjO3TB5C3ekiCIp7hlPAcaaZHTkfU; XSRF-TOKEN=eyJpdiI6IjhvVFpWMWtwMm0vU1RKNHB2VzdMdUE9PSIsInZhbHVlIjoiaDNEWTlhcTBRTWI0aXhkaU54Z3I5VndoWFg4Q1A1WmpJUDI1S2hFRGtiMUUwYUl0OEN6S0Q3RVFDZDJXSTNvdTllUXMzN0o1RU94blpqVTdpdTcxaTVvZjlwdFk2Z3djeldteHp0R3Q4UEVjMEovbGk2SHJnVXZmbzRBUzI1RHkiLCJtYWMiOiI2MDMyYzFjNWVjODY4NjRjMTk4NGNmMmI3Yjg4M2VjYzU5YzcwZGRkNDIxMTRiOTc1N2FkMmQ2NTc4YTA5MjhiIiwidGFnIjoiIn0%3D
> Content-Type: multipart/form-data; boundary=X-INSOMNIA-BOUNDARY
> Accept: application/json
> Content-Length: 293
| --X-INSOMNIA-BOUNDARY
| Content-Disposition: form-data; name="product_id"
| 1
| --X-INSOMNIA-BOUNDARY
| Content-Disposition: form-data; name="amount"
| 1
| --X-INSOMNIA-BOUNDARY
| Content-Disposition: form-data; name="_token"
| YgKRkQc9D5GWOPiP8zqVEcoA4FuvESf02SSjy7U3
| --X-INSOMNIA-BOUNDARY--
我完全不明白为什么我在api路由中使用web中间件。api中间件将为我生成以下500条错误消息:
"message": "Session store not set on request.",
这是我的axios请求:
axios.get('http://localhost:8000/api/get-token').then(response => {
const _token = response.data._token
const bodyFormData = new FormData()
bodyFormData.append('product_id', product.id)
bodyFormData.append('_token', _token)
const headers = {
'Content-Type': 'multipart/form-data',
'Access-Control-Allow-Credentials': true,
'_token': _token
}
axios({
method: "post",
url: 'cart',
data: bodyFormData,
headers: headers,
}).then((res) => {
console.log('res',res)
}).catch((err) => {console.log(err)})
});
这真是一篇很长的文章。我希望我已经提供了所有必要的信息。
- 我绝对不明白为什么我在api路由中使用web中间件。
- 这是因为API路由没有为应用启用会话,因为它期望应用使用令牌,所以为了使用会话,你需要有"Web"中间件
令牌不匹配错误可能是因为通过get-token端点生成/提供的令牌不是正确的
- 我看到的解决方案是添加/购物车路由作为CSRFTokenMatch的例外路由,打开App/Http/Middleware/VerifyCsrfToken.php文件并在受保护的$except数组中添加路由。这不是一件理想的事情,但这将解决你的问题,并帮助你继续前进。
另一个使你的应用程序安全的选择是使用Laravel Sanctum并为每个来宾用户生成一个令牌(使用来宾模型),如果你需要帮助,我可以解释更多,但这是一个有点不同的场景
我的第一个猜测是你没有发送cookie,需要做
axios.defaults.withCredentials = true
或者,更安全(因为它限制了withCredentials
在您真正想要使用它的时候):
const axiosWithCredentials = axios.create({
withCredentials: true
});
axiosWithCredentials.get('http://localhost:8000/api/get-token').then(response => {
const _token = response.data._token
const bodyFormData = new FormData()
bodyFormData.append('product_id', product.id)
bodyFormData.append('_token', _token)
const headers = {
'Content-Type': 'multipart/form-data',
'Access-Control-Allow-Credentials': true,
'_token': _token
}
axiosWithCredentials({
method: "post",
url: 'cart',
data: bodyFormData,
headers: headers,
}).then((res) => {
console.log('res',res)
}).catch((err) => {console.log(err)})
});