禁用 Laravel 中特定路由的 CSRF。

79

我有一个支付系统,其中数据被提交到第三方站点,然后再被带回来...

当数据返回时,它会命中一个特定的URL,比如说/ok路由。 $_REQUEST['transaction'].

但是由于Laravel中间件,我遇到了令牌不匹配的问题。第三方支付API无法生成令牌,那么我该怎么禁用它呢?只为此路由?

还是有更好的选择吗?

Route::get('/payment/ok',   'TransactionsController@Ok');
Route::get('/payment/fail', 'TransactionsController@Fail');

public function Ok( Request $request )
{
    $transId = $request->get('trans_id');

    if ( isset( $transId ) )
    {

        return $transId;

    }

}

3
http://laravel.com/docs/master/routing#csrf-excluding-uris - Rashi
你使用的是哪个版本的Laravel?如果是5.1,请参考下面的答案。如果是旧版本,请告诉我,我会更新答案,因为对于旧版本有一些方法可以实现,只是稍微复杂一些。 - jedrzej.kurylo
1
@jedrzej.kurylo 请问如何在Laravel 5.0中禁用CSRF令牌。 - Cataclysm
3个回答

159

自从版本5.1起,Laravel的VerifyCsrfToken中间件允许指定不需要进行CSRF验证的路由。为了实现这一点,您需要在App\Http\Middleware\VerifyCsrfToken.php类中将这些路由添加到$except数组中:

<?php namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

class VerifyCsrfToken extends BaseVerifier
{
  protected $except = [
    'payment/*',
  ];
}

有关更多信息,请参见文档


嗨Jedrzej,我之前用过上述方法,但是它不适用于laravel 5.2。我需要知道如何禁用API路由的CSRF令牌,以便针对laravel 5.2版本有类似的解决方案。 - sankar muniyappa
1
在5.2中排除URI的方法与此相同-请参阅此处的文档 https://laravel.com/docs/5.2/routing#csrf-excluding-uris - jedrzej.kurylo

40

从 Laravel 7.7 开始,你可以使用 withoutMiddleware 方法,例如:

Route::get('/payment/ok',   'TransactionsController@Ok')
    ->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

Route::get('/payment/fail', 'TransactionsController@Fail')
    ->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

1
您应该向app/Http/Kernel.php $routeMiddleware数组中添加csrf字段,如下所示:'csrf' => VerifyCsrfToken::class - Ozal Zarbaliyev
正如@ozal-zarbaliyev所提到的,没有名为csrf的中间件。只需在withoutMiddleware函数中使用\App\Http\Middleware\VerifyCsrfToken::class即可。 - Sadegh PM

6

@jedrzej.kurylo所描述的技术能够很好地排除一个或两个页面。

如果你需要从CSRF验证中排除许多页面并更具有未来性,这里有一种不同的技术。

你可以将路由进行分段,并对每个路由应用不同的中间件。因此,你可以将付款路由放入单独的路由组中,并且不对它们应用VerifyCsrfToken。下面是实现方法。

1. 创建路由文件

你会发现在你的routes目录中,你有以下树形结构:

  • routes/
  • routes/api.php
  • routes/web.php

在这里创建一个新文件,routes/payment.php,并将你的路由添加到其中:

<?php
use Illuminate\Support\Facades\Route;

Route::get('/payment/ok',   'TransactionsController@Ok');
Route::get('/payment/fail', 'TransactionsController@Fail');

2. 使用RouteServiceProvider处理路由

Laravel的路由由app\Providers\RouteServiceProvider.php处理。你会注意到这些函数:map()mapWebRoutes()。根据需要在此文件中添加相应内容(为简洁起见,我省略了原有注释)。

    public function map()
    {
        $this->mapApiRoutes();
        $this->mapWebRoutes();
        $this->mapPaymentRoutes(); // <---- add this line
    }

    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }

    protected function mapPaymentRoutes()  // <--- Add this method
    {
        Route::middleware('payment')       // <--- this line is important
             ->namespace($this->namespace)
             ->group(base_path('routes/payment.php'));
    }

请注意,我们增加了一个新的中间件层。这对于下一步很重要。

3. 添加新的中间件层

您的路由组的中间件定义在 App\Http\Kernel.php 中。

更新 $middlewareGroups 属性,并为 'payment' 添加一个中间件条目。它可以与 web 完全相同,但不包括 VerifyCsrfToken 行。

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\NoClickjack::class,
            \App\Http\Middleware\SecureReferrerPolicy::class,
            \App\Http\Middleware\NoXssScripting::class,
        ],

        // ********** Add this *******************
        'payment' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,

// This is the line you want to comment-out / remove
//            \App\Http\Middleware\VerifyCsrfToken::class,     

            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\NoClickjack::class,
            \App\Http\Middleware\SecureReferrerPolicy::class,
            \App\Http\Middleware\NoXssScripting::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

现在,每当您添加需要从CSRF令牌检查中排除的新路由时,请将它们添加到routes/payment.php文件中。

7
我会把这称为过度设计。 - Orkhan Alikhanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接