Laravel: workaround the CSRF token via Ajax issue

2019-09-08 17:56发布

问题:

Scenario:

I want via ajax send chosen words to a Controller, but I am getting all the time "Internal server error" After a full Sunday of struggling and swearing I think I know why this is happening and how it could be solved. I dont have that problem if I send the word via a ordinary Form and Submit button. The issue is the mis-marriage between Ajax and the CSRF token mismatch.

So here is the Ajax snippet>

<script>    
    $(document).ready(function(){           
            $('.choose-language').on('click', function(e){
            e.preventDefault();
            var selectedlanguage = $(this).data('value');
            alert(selectedlanguage); // it gets the value alright on clicking the paragraph
            $.ajax({  // so I want to send it to the controller
            type:"POST",  // via post 
            url: 'language',  // correct?
            data:{'locale': selectedlanguage},

            });   // HERE FINISHES THE $.POST STUFF           

        }); //HERE FINISHES THE CLICK FUNCTION       

    }); // HERE FINISHES THE DOCUMENT AND READY STUFF
    </script>    

Here is the HTML

<div class="choose-language">
<p class="choose-language" id="english" data-value="en" >English</p>
<p class="choose-language" id="spanish" data-value="es" >Spanish</p>
</div>

Here is the Routes:

Route::get('/', function () {
    return view('welcome');
});

Route::post('language', array(

   'as'   =>'language',
   'uses' => 'LanguageController@changelanguage'

));

And the Controller

class LanguageController extends Controller

{

     public function changelanguage()
    {
        Session::set('locale', \Input::get('locale'));              
        return \Redirect::back();

    }

}

So, if I go to Middleware, I can see there is a File called VerifyCSRFToken.php and inside that file there is this:

class VerifyCsrfToken extends BaseVerifier
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        // code here
    ];
}

So, I am sure that should fix it, but I wrote 'language' where the // code here is and did not make any difference. There must be other bugs..

Thanks a lot.

UPDATE:

I have found a typo (apologies I had written redirecto instead of redirect) and I m not getting errors anymore.

回答1:

Add the CSRF token to your HTML head:

<meta name="csrf-token" content="<?= csrf_token() ?>">

Add this to your JS file:

$.ajaxSetup({
    headers: {
        'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
    }
});

The CSRF should now pass the middleware



回答2:

There was one annoying thing in this HMTL code: as you see the class "choose-language" was repeated also in the div, which caused the click to be repeated twice, and the second time without actually sending a value. So I have left it there for you to see, but you do need to remove it. Once you remove it from the div, the code works correctly. So this responds and solves the issue of Ajax and Laravel CSRF. I have tested the output of the controller and it gets the word sent. Before Laravel 5.0 you had to go through a lot of hacking in the code and fix the bugs and add also conditionals in the filter to let decide when CSRF was or not coming from an Ajax, besides having to add code in every header of every page where you had Ajax sending something etc.

Now, in Laravel 5.0 you just do as I wrote in the code and you are done.



标签: laravel-5