Laravel捕获TokenMismatchException
TokenMismatchException可以使用try catch块捕获吗? 而不是显示debugging页面,显示“TokenMismatchException VerifyCsrfToken.php行46 …”,我希望它显示实际的页面,只是显示一个错误信息。
我没有与CSRF的问题,我只是希望它仍然显示页面,而不是debugging页面。
复制(使用Firefox):步骤:
- 打开页面( http://example.com/login )
- 清除Cookies(域,path,会话)。 我在这里使用web开发工具栏插件。
- 提交表格。
实际结果:“哎呀,看起来像是出了问题”页面显示。 预期结果:仍然显示login页面,然后传递“令牌不匹配”的错误或其他东西。
请注意,当我清除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>
这里没有什么真正的想法。 只是一个普通的forms。 就像我所说的,表单工作得很好。 正是当我说明上述步骤时,由于TOKEN过期而出错。 我的问题是,如果这种forms的行为呢? 我的意思是,当我清除cookies和会话时,我需要重新加载页面呢? CSRF是如何在这里工作的?
您可以处理App \ Exceptions \ Handler.php中的TokenMismatchExceptionexception
<?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解决scheme
在App \ Exceptions \ 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); }
我也很喜欢这个想法:
而不是试图抓住例外,只是将用户redirect到同一页面,并使他/她再次重复行动。
在App \ 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轻松处理客户端响应,例如通过显示消息和刷新页面。 不要忘记在jQuery ajaxComplete事件中捕获HTML状态码:
$(document).ajaxComplete(function(event, xhr, settings) { switch (xhr.status) { case 400: status_write('Bad Response!!!', 'error'); location.reload(); } }
大声笑
BOB在AJAX请求中,您可以使用abort()函数响应客户端,然后使用AJAX jqXHR.status轻松处理客户端响应,例如通过显示消息和刷新页面。 不要忘记在jQuery ajaxComplete事件中捕获HTML状态码: