Ошибка Laravel 419 - проблема VerifyCsrfToken
У меня есть несколько сайтов Laravel, размещенных на одном сервере. С последним сайтом, который я создал, контактная форма отказывается отправить, не выдавая ошибку 419. Я настроил маршрутизацию в своем файле web.php, как и на других веб-сайтах, на которых есть действующие рабочие контактные формы, и я генерирую и отправляю токен точно так же, {{ csrf_field() }}
,
Я нашел ответ на аналогичный вопрос о том, что вы можете отключить проверку Csrf, добавив записи в $except
массив в app/Http/Middleware/VerifyCsrfToken.php
, Я проверил, что это действительно разрешает ошибку 419:
protected $except = [
'contact',
'contact*',
];
Но, конечно, я хочу сохранить функциональность Csrf, и я только обновил $except
массив для устранения неисправностей.
Кто-нибудь знает, что может отличаться в новой среде Laravel, которая будет иметь такое поведение 419, несмотря на передачу сгенерированного токена? Я пытался обновить ряд настроек ENV и переключать разные вещи, но ничего кроме изменения $except
Массив оказал какое-либо влияние на проблему.
Обновить
Поскольку до сих пор было небольшое обсуждение, я решил предоставить дополнительную информацию и код.
Во-первых, это форма Ajax, но пока не выпрыгивайте со своего места. Я тестировал форму как с, так и без ajax. Если я хочу протестировать с ajax, я просто нажимаю кнопку, подключенную к слушателю jQuery. Если нет, я изменяю или удаляю идентификатор кнопки, или запускаю $("#formName").submit();
в окне консоли.
Выше (ajax, старомодный способ отправки и селектор jquery с .submit();
) все приводят к одному и тому же ответу - ошибка 419.
И для полноты, вот мой код ajax, который работает на всех других веб-сайтах, которые я размещаю. Я определил массив postData, чтобы сохранить все в порядке, и я добавил console.log()
оператор сразу после него, чтобы (снова) подтвердить, что токен сгенерирован очень хорошо и правильно передается с запросом.
var postData = {
name: $("#name").val(),
email: $("#email").val(),
message: $("#message").val(),
_token: $("input[name=_token]").val()
};
console.log(postData);
$.post("/contact", postData, function (data) {
...
Есть идеи? Может ли быть проблема конфигурации с моим ENV или другим файлом?
Обновление прогресса!
Поскольку другие сайты работают просто отлично, я клонировал старый сайт и просто переписал файлы, которые я изменил для нового сайта, и бац! Теперь это работает. Делая немного больше копать, я побежал php artisan --version
на клонированной версии сайта по сравнению с нерабочей версией, и вот результаты:
Рабочая версия: Laravel Framework 5.7.3
Неработающая версия: Laravel Framework 5.7.9
Возможно, это ошибка с Laravel? Или, возможно, некоторые пакеты на моем сервере устарели и требуют обновления для работы с новой версией Laravel?
9 ответов
TL; DR: этот пост содержит множество потенциальных проблем и исправлений; он предназначен для тех, кто ищет соответствующую бонусную информацию, когда застревает.
Я только что столкнулся с этой ошибкой, используя Laravel Sanctum в том, что выглядит как неправильно настроенное промежуточное ПО. Sanctum используетauth:sanctum
промежуточное ПО для сторожа, которое является своего рода расширением auth
Guard, который Laravel использует по умолчанию, но сеанс обрабатывается web
группа промежуточного программного обеспечения.
Я не могу точно выразить словами некоторые из этих внутренних вещей Laravel; На данный момент у меня больше опыта с JavaScript, чем с PHP.
В моем api.php
файла, у меня были маршруты входа / регистрации / выхода, а в моем Kernel.php
файл, я скопировал \Illuminate\Session\Middleware\StartSession::class,
из веб-группы в группу api.
Мне пришлось сделать это, чтобы исправить мой модульный тест входа в систему, который выдавал ошибку "Хранилище сеансов не по запросу". Копирование, которое позволило мнеpostJson
запрос на работу в модульном тесте, но через некоторое время я начал видеть сообщение об ошибке 419 CSRF из приложения JavaScript (что плохо, потому что раньше оно работало нормально).
Я начал преследовать некоторые отвлекающие маневры разрешения файловой системы в /storage/framework/sessions
папка, но проблема была не в этом (для меня).
Позже я выяснил, что с Laravel Sanctum и по умолчанию AuthenticatesUsers
черта, вы должны использовать web
охранник для авторизации, а auth:sanctum
промежуточное ПО для защищенных маршрутов. Я пытался использоватьapi
защита для маршрутов аутентификации, и это было центральным элементом моих 419 ошибок с чертой AuthenticatesUsers.
Если кто-то получит 419, пока CSRF работал или должен работать, я рекомендую сделать несколько \Log::debug()
исследования во всех ключевых точках вашей системы, где они вам нужны:
Auth::check()
Auth::user()
Auth::logout()
Если вы наблюдаете странное поведение с ними, по моим наблюдениям, что-то не так с вашей конфигурацией, связанной с sessions
или что-то не так с вашей конфигурацией, связанной с web
, api
охранники.
Охранники имеют отношение к AuthManager
guard, который поддерживает состояние нескольких запросов и нескольких модульных тестов.
Это лучшее описание, которое я нашел, на изучение которого у меня ушла больше недели:
Метод Illuminate\Auth\RequestGuard::logout не существует Laravel Passport
В качестве случайного последнего примера, если ваш сеанс каким-то образом генерирует токен CSRF, используя данные из web
группа промежуточного программного обеспечения, пока ваши маршруты настроены на использование api
, они могут неправильно интерпретировать полученный CSRF.
Кроме того, откройте инструменты разработчика Chrome, перейдите на вкладку "Приложения" и посмотрите файлы cookie. Убедитесь, что у вас естьXSRF-TOKEN
cookie как незащищенный (т.е. не httpOnly).
Это позволит вам иметь перехватчик запросов Axios, например:
import Cookies from 'js-cookie';
axios.interceptors.request.use(async (request) => {
try {
const csrf = Cookies.get('XSRF-TOKEN');
request.withCredentials = true;
if (csrf) {
request.headers.common['XSRF-TOKEN'] = csrf;
}
return request;
} catch (err) {
throw new Error(`axios# Problem with request during pre-flight phase: ${err}.`);
}
});
Вот так успешно работает мой текущий Laravel/Vue SPA.
Раньше я также использовал эту технику здесь:
app.blade.php (корневой файл макета, заголовок документа)
<meta name="csrf-token" content="{{ csrf_token() }}">
bootstrap.js (или где угодно)
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
const token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
На мой взгляд, большинство проблем возникает из-за неправильного значения в одном или нескольких из этих файлов:
./.env
./config/auth.php
./config/session.php
Обратите особое внимание на такие вещи, как SESSION_DOMAIN, SESSION_LIFETIME и SESSION_DRIVER, и, как я уже сказал, разрешения файловой системы.
Проверьте свой nginx access.log
и / или error.log
файл; они могут содержать намек.
Возможно, ваш домен в адресной строке браузера не совпадает domain
ключ в config/session.php
config или SESSION_DOMAIN
в вашем файле env.
Только что нашел вашу проблему в рамках репо. Это не проблема laravel, в вашей установке отсутствуют права на запись в папку хранилища, поэтому laravel не может записывать сеанс, журналы и т. Д.
Вы получаете ошибку 419, потому что вы не можете записать в файлы, таким образом, вы не можете создать сессию n, поэтому вы не можете проверить токен csrf.
Быстрая починка: chmod -R 777 storage
Правильное исправление: переместите вашу установку в папку, в которую nginx/apache/ ваш пользователь может написать. Если вы используете nginx/apache, перенесите туда свое приложение и предоставьте необходимые права на проект (chown -R www-data: /path-to-project)
Если вы используете php artisan serve, измените его разрешения для вашего пользователя: chown -R $(whoami) /path-to-project
Вы понимаете, пусть писатели пишут, и у вас все хорошо.
У меня была такая же проблема, но в моем случае проблема была в https. Форма была на http-странице, но действие было на https. В результате сеанс отличается, что вызывает ошибку csrf.
Я использовал одно и то же имя приложения для staging и prod, будучи поддоменом prod. После изменения имени приложения в постановке это сработало
У нас была эта проблема, оказалось, что нашsessions
table не соответствовал используемой нами версии Laravel. Я бы порекомендовал посмотреть, заполняется ли он или остается пустым (как у нас).
Если он пуст, даже если у вас есть люди, посещающие сайт, я бы сказал, что проблема именно в этом.
(Если вы не используете базу данных для хранения своих сеансов , очевидно, я бы предложил вместо этого проверять, где бы вы ни находились.)
Ознакомьтесь с моим ответом на этот вопрос, поможет ли он в том, чего вы пытаетесь достичь. Ошибка возврата запроса на отправку формы 419 unknown status laravel
Проверить этот код
Route::get('/contact', [
'uses' => 'ContactController@index',
'nocsrf' => true,
]);
Route::post('/contact', [
'uses' => 'ContactController@contactSubmit',
'nocsrf' => true,
]);
или вы можете удалить отверстие CSRF
protected $except = [
'*'
];