Laravel - 将 VerifyCsrfToken 添加到控制器获取 ajax 请求

Posted

技术标签:

【中文标题】Laravel - 将 VerifyCsrfToken 添加到控制器获取 ajax 请求【英文标题】:Laravel - adding VerifyCsrfToken to controller getting ajax request 【发布时间】:2018-05-24 11:32:32 【问题描述】:

我正在创建一个接收 AJAX 请求的控制器,并且从 Laravel 文档中,我可以发送带有 X-Csrf 令牌的标头 https://laravel.com/docs/5.5/csrf#csrf-x-csrf-token

在我的控制器上我有这样的东西:

 public function checkPromotion(Request $request)


    try 
        $this->middleware('VerifyCsrfToken');
    
    catch (TokenMismatchException $e)
        return response()->json(['error' => 'Error Token Provided']);
    



当我尝试向这个控制器发送一个空白的发布请求时,响应是空白的。

【问题讨论】:

【参考方案1】:

这里有三个问题:

    如果要在控制器中添加中间件,则必须在构造函数中进行。

    开箱即用,您无法在控制器操作中处理中间件异常。您需要在您的 \App\Exceptions\Handler 课程中使用 handle the exception。当令牌验证失败时,该类的handle 方法将收到TokenMismatchException

    字符串'VerifyCsrfToken' 不是引用中间件的有效方式。

关于#3,middleware 方法采用middleware group 的名称,或特定中间件的 FQCN。

以下应该有效:

$this->middleware(\App\Http\Middleware\VerifyCsrfToken::class)

(我假设您使用的是默认的 App 命名空间)

如果你得到一个“Session store not set on request”异常,那是因为没有 StartSession 中间件就不能使用 CSRF 中间件。

您真正想要的很可能是网络中间件:

$this->middleware('web')

这将包括 CSRF 中间件、会话启动中间件和其他一些中间件(有关详细信息,请参阅您的 http 内核)。

如果需要,您可以在 VerifyCsrfToken 类中使用 $except 数组 exclude routes from CSRF verification

【讨论】:

我试过了,仍然得到空白响应尝试 $this->middleware(VerifyCsrfToken::class); catch (TokenMismatchException $e) return response()->json(['error' => 'Error Token Provided']); @user2873860 你导入了VerifyCsrfToken吗? 它不起作用,我尝试了两种方式 if (!$this->middleware(VerifyCsrfToken::class)) return response()->json(['error' => 'Error Token假如']); 尝试 $this->middleware(VerifyCsrfToken::class); catch (TokenMismatchException $e) return response()->json(['error' => 'Error Token Provided']); @user2873860 刚刚注意到您在控制器操作中添加中间件,您必须在构造函数中进行。 我尝试添加类构造,在 Request.php 行 905 中显示 RuntimeException 错误:未按请求设置会话存储。但是我需要以一种方法而不是整个班级使用它,有什么办法吗?【参考方案2】:

Controller 上的 middleware 方法正在控制器上的数组中注册一个中间件。那个中间件当时没有运行。

当在构造函数中调用此方法时,在控制器被解析为能够构建当前路由/操作所需的中间件堆栈后,路由器/路由集合将有权访问getMiddleware 方法。

您可能希望在异常处理程序App\Exceptions\Handler 中处理此异常。

Laravel 5.5 Docs - Errors - The Exception Handler - Render Method

public function render($request, Exception $exception)

    if ($exception instanceof \Illuminate\Session\TokenMismatchException) 
        return response()->json(['error' => 'Error Token Provided']);
    

    return parent::render($request, $exception);

【讨论】:

你能解释一下我是如何处理 App\Exceptions\Handler 的吗? 当表单提交给控制器时,laravel 默认如何验证它的令牌,我需要让我的控制器处理 ajax 请求,因为它是一个表单,需要一个令牌头 正如 mtinsley 指出的 web 中间件组...它提供会话和 VerifyCsrfToken 中间件...您在routes/web.php 中的所有路由应该已经拥有整个web 中间件组默认应用【参考方案3】:
protected function tokensMatch($request)

    // If request is an ajax request, then check to see if token matches token provider in
    // the header. This way, we can use CSRF protection in ajax requests also.
    $token = $request->ajax() ? $request->header('X-CSRF-Token') : $request->input('_token');

    return $request->session()->token() == $token;

在VerifyCsrfToken.php中添加这个函数

【讨论】:

以上是关于Laravel - 将 VerifyCsrfToken 添加到控制器获取 ajax 请求的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Laravel 安装程序“laravel/installer”更新到最新版本?

无法将 Laravel 连接到 MailChimp(laravel 5.4)

vue.js 和 Laravel - 我们如何将 vue js 与 laravel 集成?

如何将 Laravel 身份验证添加到已启动的 Laravel 项目中?

Laravel - 为啥 laravel 要求将 .env.example 重命名为 .env 而 .env 已经存在?

如何将“Phpmyadmin”添加到 laravel 帆(docker + laravel)-自动:回答