CSRF Token Duplication on Vue Router Laravel 5.3 V

2019-07-24 20:52发布

问题:

So my problems is that the session token is generated.

and the token that i've sent via AJAX or AXIOS (cause im using vue and vue router for fetching API)

is getting a mismatch

This is the response i got when posting data

The ajax token is equal to the token in the meta tag of the main blade template

using this tag

Meta Tag in app.blade.php

<meta name="csrf-token" content="{{ csrf_token() }}">
<script>
    window.Laravel = <?php echo json_encode([
        'csrfToken' => csrf_token(),
    ]); ?>
</script>

Interceptor of Axios (purpose is to inject the csrf_token from the meta Tag)

Vue.axios.interceptors.request.use(function (config) {

    config.headers['X-CSRF-TOKEN'] = Laravel.csrfToken;
    console.log(config);
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
});

Response:

array:1 [
  "SessionToken" => "JfhmtCaTiQ49BtF2VK3TysvYnEQSE9n5i1uiHegO"
]
array:1 [
  "AjaxToken" => "WqKOiaunbvJbxIsnEjetFoCm1mvdUYESRqfXO2lv"
]

VerifyCSRFToken middleware method:

  protected function tokensMatch($request)
    {
        $sessionToken = $request->session()->token();

        $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');

        dd(['SessionToken' => $sessionToken],['AjaxToken' => $token]);
        if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
            $token = $this->encrypter->decrypt($header);
        }

        if (! is_string($sessionToken) || ! is_string($token)) {
            return false;
        }

        return hash_equals($sessionToken, $token);
    }

So i came up with this idea but its not working because its the token that im getting from the api is null or empty

Here is the method from my RegisterComponent.vue

    submitForm() {
        this.axios.get('/token')
            .then(response => {
               this._token = response.data
                   this.axios.post('/register',this.data)
                        .then(responseNew => {
                            console.log(responseNew.data);
                        })
                        .catch(responseNew => {
                            this.errors = responseNew.data;
                        })
            });
    }

as you can see im getting a token from my api.php in routes folder

and im also using the authentication api of Laravel and put it on the api routes too

Here is the api.php

Route::group(['middleware' => 'web'], function() {
    Auth::routes();
});

Route::get('/token',function() {
   dd(csrf_field());
});
Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:api');

Route::resource('/users','UserController');

Route::group(['middleware' => 'auth'], function () {


Route::resource('/stores','StoreController');

Route::resource('/items','ItemController');

Route::resource('/transactions','StoreController');

Route::resource('/managers','ManagerController');

Route::resource('/employees','EmployeeController');

Route::resource('/customers','CustomerController');

Route::resource('/tags','TagController');

});

So how can i prevent it from generating that token that will cause mismatch?

Anyone answering this will surely help the authentication of my SPA ( Single Page App)

and its also giving me response status 302

回答1:

You seem to have a bit misunderstanding. You have the csrf token configured for axios, so every request will have a header field containing the token, then you just need to make sure every request goes through laravel's csrf token validation function before it reaches your business logic, that's all you need to do to prevent csrf. The get('/token') before post('/register') seems unnecessary.

Also, talking about the /token route itself, csrf_field is not appropriate here, since it generates a hidden form field (another way to send csrf token apart from what we talked about earlier) to be embedded in a .php file like <form>...<?=csrf_field()?>...</form> => <form>...<input type="hidden" name="laravel_csrf_token" value="***">...</form>, which makes it meaningless to request csrf_field's result via xhr.