Каков наилучший способ обработки истекших жетонов в laravel 5.
Я имею в виду, что у меня есть страница, и у нее есть ссылки, которые выполняют запросы ajax. Они работают нормально, когда страница загружается, но когда я жду какое-то время, я получаю ошибку TOKEN MISMATCH.
Теперь мне нужно обновить страницу, чтобы она снова работала. НО, я не хочу обновлять страницу. Я хочу, чтобы какой-то способ обновить токен или какую-то другую работу, чтобы исправить ошибку.
Надеюсь, ты понял.
работа для него, заключается в том, чтобы фактически получить новый токен в определенное время, иначе вы побеждаете цель токена csrf:
<html> <head> <meta name="csrf_token" content="{{ csrf_token() }}"> </head> <body> <script type="text/javascript"> var csrfToken = $('[name="csrf_token"]').attr('content'); setInterval(refreshToken, 3600000); // 1 hour function refreshToken(){ $.get('refresh-csrf').done(function(data){ csrfToken = data; // the new token }); } setInterval(refreshToken, 3600000); // 1 hour </script> </body> </html>
В маршрутах laravel
Route::get('refresh-csrf', function(){ return csrf_token(); });
Я прошу прощения в случае каких-либо синтаксических ошибок, не использовал jquery в течение длительного времени, но я думаю, вы поняли идею
Я объединяю 2 вещи для этого случая:
1. Увеличьте продолжительность сеанса
//In config/session.php replace this: 'lifetime' => 120 //with: 'lifetime' => 360
Время жизни по умолчанию Laravel 5 равно 120 (минутам), вы можете изменить его на любое значение, например, 360 (6 часов)
2. Поймать исключение и отобразить сообщение об ошибке
//In app/Exceptions/Handler.php replace this: public function render($request, Exception $e) { if ($e instanceof ModelNotFoundException) { $e = new NotFoundHttpException($e->getMessage(), $e); } return parent::render($request, $e); } //with: public function render($request, Exception $e) { if ($e instanceof ModelNotFoundException) { $e = new NotFoundHttpException($e->getMessage(), $e); } if ($e instanceof \Illuminate\Session\TokenMismatchException) { return redirect('/')->withErrors(['token_error' => 'Sorry, your session seems to have expired. Please try again.']); } return parent::render($request, $e); }
Поэтому в основном вы перенаправляете пользователя на корень «/» (вы можете изменить его на любой путь) с сообщением об ошибке, и на этой странице вы должны сделать это, чтобы отобразить сообщение об ошибке:
@if ($errors->has('token_error')) {{ $errors->first('token_error') }} @endif
Я думаю, что ответ от @UX Labs вводит в заблуждение. И тогда комментарий от @jfadich кажется совершенно неправильным.
Для Laravel 5.4 в мае 2017 года я решил проблему следующим образом:
В web.php
:
Route::post('keep-token-alive', function() { return 'Token must have been valid, and the session expiration has been extended.'; //https://stackoverflow.com/q/31449434/470749 });
В javascript, на ваш взгляд:
$(document).ready(function () { setInterval(keepTokenAlive, 1000 * 60 * 15); // every 15 mins function keepTokenAlive() { $.ajax({ url: '/keep-token-alive', //https://stackoverflow.com/q/31449434/470749 type: 'post', headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }).then(function (result) { console.log(new Date() + ' ' + result + ' ' + $('meta[name="csrf-token"]').attr('content')); }); } });
Обратите внимание, что вы не должны VerifyCsrfToken.php
'keep-token-alive'
в исключениях в VerifyCsrfToken.php
. Поскольку @ ITDesigns.eu подразумевается в комментарии, для этого маршрута важно проверить, существует ли действующий токен и что ему просто нужно продлить срок его действия.
Мой сайт Laravel позволяет пользователям смотреть видео (час), и он использует ajax для публикации своего прогресса каждую минуту.
Но многие пользователи загружают страницу, а затем не запускают видео до много часов спустя.
Я не знаю, почему они оставляют свою вкладку браузера открытой до того, как смотреть, но они это делают.
И тогда я получу тонны исключений TokenMismatch в своих журналах (и пропустил бы данные о их прогрессе).
В session.php
я изменил 'lifetime'
с 120 до 360 минут, но этого было недостаточно. И я не хотел делать это дольше 6 часов. Поэтому мне нужно было включить эту страницу, чтобы часто расширять сеанс с помощью ajax.
В web.php
:
Route::post('refresh-csrf', function() {//Note: as I mentioned in my answer, I think this approach from @UX Labs does not make sense, but I first wanted to design a test view that used buttons to ping different URLs to understand how tokens work. The "return csrf_token();" does not even seem to get used. return csrf_token(); }); Route::post('test-csrf', function() { return 'Token must have been valid.'; });
В javascript, на ваш взгляд:
<button id="tryPost">Try posting to db</button> <button id="getNewToken">Get new token</button> (function () { var $ = require("jquery"); $(document).ready(function () { $('body').prepend('<div>' + new Date() + ' Current token is: ' + $('meta[name="csrf-token"]').attr('content') + '</div>'); $('#getNewToken').click(function () { $.ajax({ url: '/refresh-csrf', type: 'post', headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }).then(function (d) { $('meta[name="csrf-token"]').attr('content', d); $('body').prepend('<div>' + new Date() + ' Refreshed token is: ' + $('meta[name="csrf-token"]').attr('content') + '</div>'); }); }); $('#tryPost').click(function () { $.ajax({ url: '/test-csrf', type: 'post', headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }).then(function (d) { $('body').prepend('<div>' + new Date() + ' Result of test: ' + d + '</div>'); }); }); }); })();
В session.php
временно измените 'lifetime'
на что-то очень короткое для целей тестирования.
Затем поиграйте.
Вот как я узнал, как работает токен Laravel и как нам просто нужно успешно отправлять POST на защищенный CSRF маршрут, чтобы токен оставался действительным.
Увеличьте время lifetime
ваших сеансов. Вы можете сделать это, отредактировав файл config/session.php
в своей конфигурации laravel.
/* |-------------------------------------------------------------------------- | Session Lifetime |-------------------------------------------------------------------------- | | Here you may specify the number of minutes that you wish the session | to be allowed to remain idle before it expires. If you want them | to immediately expire on the browser closing, set that option. | */ 'lifetime' => 120,
Я думаю, что лучший вариант – взять конфигурацию жизненного цикла файла config / session.php, а затем значение жизненного цикла, умноженное на 60 * 1000 в коде javascript. Используйте вспомогательную функцию config (), предоставляемую laravel, она может выглядеть так:
<script type="text/javascript"> var timeout = ({{config('session.lifetime')}} * 60) * 1000; setTimeout(function() { //reload on current page window.location = ''; }, timeout); </script>
Я знаю, что это не лучшее решение, но одно из самых простых. Просто отключите защиту CSRF для этой страницы, где пользователь проводит много времени. Например, на моем сайте они могут писать статью часами на одной странице. И это очень неприятно, если вы не можете сохранить статью из-за защиты CSRF.