Может ли TokenMismatchException быть уловлено с помощью блока try catch? Вместо отображения страницы отладки, которая показывает «TokenMismatchException в строке VerifyCsrfToken.php 46 …», я хочу, чтобы она отображала фактическую страницу и отображала сообщение об ошибке.
У меня нет проблем с CSRF, я просто хочу, чтобы он отображал страницу вместо страницы отладки.
Чтобы воспроизвести (используя firefox): Шаги:
Фактические результаты: «Показывает, что-то пошло не так». Ожидаемые результаты: покажите страницу входа в систему, затем передайте ошибку «несоответствие токена» или что-то еще.
Обратите внимание, что при очистке файлов cookie я не обновлял страницу, чтобы токен мог создать новый ключ и заставить его отключиться.
ОБНОВЛЕНИЕ (ДОБАВЛЕННАЯ ФОРМА):
<form class="form-horizontal" action="<?php echo route($formActionStoreUrl); ?>" method="post"> <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>" /> <div class="form-group"> <label for="txtCode" class="col-sm-1 control-label">Code</label> <div class="col-sm-11"> <input type="text" name="txtCode" id="txtCode" class="form-control" placeholder="Code" /> </div> </div> <div class="form-group"> <label for="txtDesc" class="col-sm-1 control-label">Description</label> <div class="col-sm-11"> <input type="text" name="txtDesc" id="txtDesc" class="form-control" placeholder="Description" /> </div> </div> <div class="form-group"> <label for="cbxInactive" class="col-sm-1 control-label">Inactive</label> <div class="col-sm-11"> <div class="checkbox"> <label> <input type="checkbox" name="cbxInactive" id="cbxInactive" value="inactive" /> <span class="check"></span> </label> </div> </div> </div> <div class="form-group"> <div class="col-sm-12"> <button type="submit" class="btn btn-primary pull-right"><i class="fa fa-save fa-lg"></i> Save</button> </div> </div> </form>
Здесь нет ничего необычного. Просто обычная форма. Как и то, что я сказал, форма РАБОТАЕТ отлично. Именно после того, как я изложил вышеописанные шаги, он ошибается из-за истечения срока действия TOKEN. Мой вопрос в том, должна ли форма вести себя так? Я имею в виду, когда я очищаю файлы cookie и сеанс, мне также нужно перезагрузить страницу? Так работает CSRF?
Вы можете обработать исключение TokenMismatchException в приложении \ Exceptions \ Handler.php
<?php namespace App\Exceptions; use Exception; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Session\TokenMismatchException; class Handler extends ExceptionHandler { /** * A list of the exception types that should not be reported. * * @var array */ protected $dontReport = [ 'Symfony\Component\HttpKernel\Exception\HttpException' ]; /** * Report or log an exception. * * This is a great spot to send exceptions to Sentry, Bugsnag, etc. * * @param \Exception $e * @return void */ public function report(Exception $e) { return parent::report($e); } /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Exception $e * @return \Illuminate\Http\Response */ public function render($request, Exception $e) { if ($e instanceof TokenMismatchException){ // Redirect to a form. Here is an example of how I handle mine return redirect($request->fullUrl())->with('csrf_error',"Oops! Seems you couldn't submit form for a long time. Please try again."); } return parent::render($request, $e); } }
Лучшее решение Laravel 5
в приложении \ Исключения \ Handler.php
Верните пользователя в форму с новым действительным токеном CSRF, чтобы они могли просто повторно отправить форму, не заполнив форму снова.
public function render($request, Exception $e) { if($e instanceof \Illuminate\Session\TokenMismatchException){ return redirect() ->back() ->withInput($request->except('_token')) ->withMessage('Your explanation message depending on how much you want to dumb it down, lol!'); } return parent::render($request, $e); }
заpublic function render($request, Exception $e) { if($e instanceof \Illuminate\Session\TokenMismatchException){ return redirect() ->back() ->withInput($request->except('_token')) ->withMessage('Your explanation message depending on how much you want to dumb it down, lol!'); } return parent::render($request, $e); }
Мне также очень нравится эта идея:
Вместо того, чтобы пытаться поймать исключение, просто перенаправите пользователя на ту же страницу и снова повторите действие.
Используйте этот код в приложении \ Http \ Middleware \ VerifyCsrfToken.php
<?php namespace App\Http\Middleware; use Closure; use Redirect; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier; class VerifyCsrfToken extends BaseVerifier { /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ // ]; public function handle( $request, Closure $next ) { if ( $this->isReading($request) || $this->runningUnitTests() || $this->shouldPassThrough($request) || $this->tokensMatch($request) ) { return $this->addCookieToResponse($request, $next($request)); } // redirect the user back to the last page and show error return Redirect::back()->withError('Sorry, we could not verify your request. Please try again.'); } }
Laravel 5.2: измените App \ Exceptions \ Handler.php следующим образом:
<?php namespace App\Exceptions; use Exception; use Illuminate\Validation\ValidationException; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Database\Eloquent\ModelNotFoundException; use Symfony\Component\HttpKernel\Exception\HttpException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Session\TokenMismatchException; class Handler extends ExceptionHandler { /** * A list of the exception types that should not be reported. * * @var array */ protected $dontReport = [ AuthorizationException::class, HttpException::class, ModelNotFoundException::class, ValidationException::class, ]; /** * Report or log an exception. * * This is a great spot to send exceptions to Sentry, Bugsnag, etc. * * @param \Exception $e * @return void */ public function report(Exception $e) { parent::report($e); } /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Exception $e * @return \Illuminate\Http\Response */ public function render($request, Exception $e) { if ($e instanceof TokenMismatchException) { abort(400); /* bad request */ } return parent::render($request, $e); } }
В запросах AJAX вы можете отвечать клиенту с помощью функции abort (), а затем обрабатывать ответ на стороне клиента с помощью AJAX jqXHR.status очень легко, например, показывая сообщение и обновляя страницу. Не забудьте поймать код статуса HTML в событии jQuery ajaxComplete:
$(document).ajaxComplete(function(event, xhr, settings) { switch (xhr.status) { case 400: status_write('Bad Response!!!', 'error'); location.reload(); } }
лол
BOB. В запросах AJAX вы можете отвечать клиенту с помощью функции abort (), а затем обрабатывать ответ на стороне клиента с помощью AJAX jqXHR.status очень легко, например, показывая сообщение и обновляя страницу. Не забудьте поймать код статуса HTML в событии jQuery ajaxComplete: