解決 csrf_field () 渲染後_token 的 value 為空的問題

storefee發表於2017-08-02

前言

  • 平時我們在使用csrf_field()或者csrf_token()來進行表單驗證時,絕對總是一馬平川,沒有任何懸念可言。也就從來沒把它太當回事。
  • 之前專案都是用的laravel5.1 LTS版本的,所以登入,驗證之類的基本都非常ok,需要多許可權就直接採用"kbwebs/multiauth": "~1.0"這個外掛包處理。也沒有在csrf身上花費過多的時間。
  • 當前專案用5.3版,之前的multiauth支援方面感覺不是特別好了,同時也發現5.3自帶這樣的功能。就進行嘗試和折騰(當然,基本都是採用下班時間做研究,不然白天工作沒產出怎麼對得起老闆啊!在研究的同時,也喜歡做些記錄,這也是上班期間無法細緻做到的地方。)

  • Providers/RouteServiceProvider.php和config/auth.php檔案中配置好對應內容(詳情參見:“[https://learnku.com/articles/5489/larval-53-multi-authority-login-correct-position](Laravel 5.3 自帶多許可權登入正確姿勢))
  • 重新整理登入頁面http://xxxx.app/admin/login,會發現首當其衝的會出現這個問題:
    Undefined variable: errors (View: /home/vagrant/Codes/kejisi/resources/views/admin/auth/login.blade.php)
  • 經查證資料,發現是缺少\Illuminate\View\Middleware\ShareErrorsFromSession::class這個中介軟體的驗證,導致$error變數無法被識別;

  • 這時,就想到新建一個新專案,採用 php artisan make:Auth命令,看看自帶的許可權認證是怎麼樣一個流程,再來對比分析來拍錯。它會自動生成路由:
    Auth::routes();
    Route::get('/home', 'HomeController@index');
    Auth::routes();
    Route::get('/home', 'HomeController@index');
  • 這些路由都是直接在web.php中生成,但是我想要的是所有與後臺相關的路由會自動轉發到route/admin.app,通過觀察Auth生成的路由好像起不到作用(算是我們分析中走了一點彎路吧)。
  • 好吧,我們再想想,既然你能將路由拆分到不同的檔案中,你就必須要知道為什麼這樣拆分,拆分後laravel是怎麼去識別哪個路由能轉發到哪個路由檔案中:
    routes
    ├── admin.php
    ├── api.php
    └── web.php
  • 這時就會馬上想到在Providers/RouteServiceProvider.php檔案中做過分類操作,
    一般情況我們會有預設生成好的方法:
    protected function mapWebRoutes()
    {
        Route::group([
            'middleware' => 'web',
            'namespace'  => $this->namespace,
        ], function ($router) {
            require base_path('routes/web.php');
        });
    }
  • 這裡面的web其實就對應著\App\Http\Kernel中的路由中介軟體分組web,同時也會把對應的路由轉發到routes/web.php中,可以發現在這裡面有一個\App\Http\Middleware\VerifyCsrfToken::class這個不就是進行csrf驗證的嗎?
  • 好,既然如此,我們在kernel.php從新建立一個路由分組,直接對應後臺的操作做驗證,是否可行呢?
    於是我們可以在進行以下2步操作:
  • 1,$middlewareGroups中加入:
    'admin' => [
        這裡可以新增我們需要的各種中介軟體
    ]

    此時,我們再次重新整理登入頁面http://xxxx.app/admin/login,會發現

    Session store not set on request.

    說明缺少Seesion相關中介軟體支援,在middlewareGroups中的admin加上\Illuminate\Session\Middleware\StartSession::class

    接著又出現下面問題:
    Undefined variable: errors (View: /home/vagrant/Codes/kejisi/resources/views/admin/auth/login.blade.php)

    這個問題依然存在。於是經過多方資料查證,發現是缺少\Illuminate\View\Middleware\ShareErrorsFromSession::class中介軟體。會導致$error變數無法被識別和解析。

  • 這時我們會發現已經可以看到久違的登入介面了。
  • 但是進行登入時,始終會出現不管怎樣始終無法登進行驗證通過,檢視頁面原始碼發現,_token的值居然為空,也就是我們標題中所提到的問題,有且僅有一個地方出現了,那就是在登入這個頁面。其他頁面的表現就如同之前5.1中一樣的行雲流水,一馬平川。在這裡始終無法進入後臺。
  • 再加上\App\Http\Middleware\VerifyCsrfToken::class,看看。終於可以正常登入了。
    但是此時,其實我們不需要登入驗證就可以進入後臺的dashboard。就必須加上對admin的登入驗證轉發中介軟體了。但是這樣一來會導致無限驗證迴圈。具體解決方法可以參見“[https://learnku.com/articles/5489/larval-53-multi-authority-login-correct-position](Laravel 5.3 自帶多許可權登入正確姿勢)
    ”。其實,回過頭重新看看kernel中
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
                ……
  • 我們會發現最簡單的方法就在眼前,就是把RouteServiceProvider.php中新增的方法寫成:
    protected function mapAdminRoutes()
    {
        Route::group([
            'namespace'  => 'App\Http\Controllers\Admin',
            'prefix'     => 'admin',
            'middleware' => 'web',
        ], function ($router) {
            require base_path('routes/admin.php');
        });
    }
  • 也就是直接通過web中介軟體進行一般的基礎驗證,這些驗證機制不正好是我們剛才在處理登入過程中碰到的各種問題所需要用到的驗證中介軟體嗎,接著再在routes/admin.php中進行路由分組,在分組中新增對admin許可權的認證。

努力是不會騙人的!

相關文章