I'm making AJAX request in Laravel with Vue.js and Vue resource.
I have view:
{{Form::open(['method' => 'post', 'class' => 'form-inline', 'id' => 'main-form'])}}
{{Form::text('param1', null, ['id' => 'param1', 'class' => 'form-control'])}}
{{Form::text('param2', null, ['id' => 'param2', 'class' => 'form-control'])}}
<input #click="sendIt($event)" type="submit" value="Check prices" class="btn btn-success btn-theme" />
{{Form::close()}}
I have js:
var Vue = require('vue');
var VueResource = require('vue-resource');
Vue.use(VueResource);
Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name=_token]').attr('content');
const app = new Vue({
el: '#app',
methods: {
sendIt: function (e)
{
e.preventDefault();
var token = $('[name="_token"]').val();
this.$http.post('/data').then((response) => {
console.log(response);
}, (response) => {
console.log(response);
});
}
}
Route:
Route::post('/data', 'MainController#data');
And controller:
public function data()
{
$msg = $this->test(); //method that retrieves data from db
return response()->json(['msg'=> $msg], 200);
}
It gives me post 500 internal server error
In response I have this headers:
Cache-Control
Content-Type
Date
Phpdebugbar-Id
Server
Status
Transfer-Encoding
X-Powered-By
In network in my data site I have response headers without token, request headers with token and I have token in Request Payload.
If I change method to get I have same error but if I change method to get and if I remove from my controller part of code where I retrieve data from db and just pass string to json (example:
$msg = 'test';
return response()->json(['msg'=> $msg], 200);
I have success and I can output test on page.
So I'm not sure if it's some problem with token or something else.
I tried and this:
var token = $('[name="_token"]').val();
this.$http.post('/prices', {_token:token})
but nothing. Same error again.
If I add this:
http: {
headers: {
X-CSRF-TOKEN: document.querySelector('#token').getAttribute('content')
}
},
I have syntax error on page load.
If I change to this:
http: {
headers: {
Authorization: document.querySelector('#token').getAttribute('content')
}
}
I got internal server error again.
And this is my token in main view:
<meta name="csrf-token" id="token" content="{{ csrf_token() }}">
<script>
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
]); ?>
</script>
EDIT:
This part works if I add quotes around x-csrf-token but still I have token mismatch error.
http: {
headers: {
'X-CSRF-TOKEN': document.querySelector('#token').getAttribute('content')
}
},
I could be mistaken but in your example at the top you have:
Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name=_token]').attr('content');
However, in your main view file you have:
<meta name="csrf-token" id="token" content="{{ csrf_token() }}">
You should be able to simply change $('meta[name=_token]') to $('meta[name=csrf-token]') (so they match).
Furthermore, the reason you had a syntax error with X-CSRF-TOKEN: ... is because you can't use hyphens in key names unless you wrap them in quotes i.e. 'X-CSRF-TOKEN': ....
Hope this helps!
Related
I am trying to fetch some reports with axios in Laravel. I tested it in Postman and everything is fine.
But here I got error 401.
Here is my code:
#Reports.vue file
<template>
<div>
<h1>All reports: </h1>
<div v-for="report in reports" v-bind:key="report.id">
<p>{{ report.description }}</p>
</div>
</div>
</template>
<script>
export default {
name: "Reports",
data () {
return {
reports : [],
}
},
mounted() {
this.fetchReports();
},
methods : {
async fetchReports() {
const {data} = await axios.get('/api/report');
this.reports = data.data;
},
}
}
</script>
#ReportController#index
public function index()
{
$reports = Report::all();
return ReportResource::collection($reports);
}
#api.php
Route::group(['middleware' => 'auth:api'], function () {
Route::apiResource('/report', 'API\ReportController');
});
Thanks in advance. If You need more informations, I will post them.
Laravels auth:api middleware require you to pass Bearer token or ?api_token= url param with your request
Source
And I don't see you passing token with your axios request
app.jss file
$('#modal-save').on('click', function(){
// geting the properties
$.ajax({
method:'POST',
url: url,
data: {body: $('#post-body').val(), postId: postId , _token: token}
})
// after done
.done(function(msg) {
$(postBodyElement).text(msg['new_body']);
$('#edit-modal').modal('hide')
});
});
my script in view code
<script>
var token = '{{ Session::token() }}';
var url = '{{ route('edit') }}';
</script>
Route file
Route::post('/edit', [
'uses'=>'PostController#postEditPost',
'as'=>'edit'
]);
My controller file
public function postEditPost( Request $request)
{
$this->validate($request,[
'body' => 'required'
]);
// checking auth user
$post = Post::find($request['postId']);
if(Auth::user != $post->user){
return redirect()->back();
}
// updating the post content
$post->body = $request['body'];
$post->update();
return response()->json(['new_body' => $post->body], 200);
}
Your'e sending an ajax request to the server, but dont accept it like so in the controller.
Try this:
// updating the post content
$post->body = $request['body'];
$post->update();
if(request()->expectsJson()){
return response()->json(['new_body' => $post->body], 200);
}
//here you can return to whereever you need it if its not ajax
return redirect('/');
Because of the VerifyCsrfToken middleware, you must provide CSRF token with each post, put, delete request.
Add meta tag inside head tag
<meta name="csrf-token" content="{{ csrf_token() }}">
Then use it in you ajax request
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
See X-CSRF-TOKEN
I want to use dropzone to upload multiple images with another form inputs
so i want a div that show the images when the user click,
also i have a button that trigger the form.
i have this but its not working
html:
<div class="col-md-12">
<h1>Upload Multiple Images using dropzone.js and Laravel</h1>
{!! Form::open([ 'route' => [ 'dropzone.store' ], 'files' => true, 'enctype' => 'multipart/form-data', 'class' => '', 'id' => '' ]) !!}
{!! Form::text('name'); !!}
<div class="dropzone" id="image-upload">
<h3>Upload Multiple Image By Click On Box</h3>
<button type="submit" class="btn btn-success" id="submit-all">
Enviar files
</button>
</div>
{!! Form::close() !!}
</div>
dropzone:
Dropzone.autoDiscover = false;
var imageUpload = new Dropzone("div#image-upload", {
url: "dropzone/store",
autoProcessQueue:false,
uploadMultiple: true,
maxFilesize:5,
maxFiles:3,
acceptedFiles: ".jpeg,.jpg,.png,.gif",
init: function() {
var submitButton = document.querySelector("#submit-all")
//imageUpload = this; // closure
submitButton.addEventListener("click", function(e) {
e.preventDefault();
e.stopPropagation();
imageUpload.processQueue(); // Tell Dropzone to process all queued files.
});
// You might want to show the submit button only when
// files are dropped here:
this.on("addedfile", function() {
// Show submit button here and/or inform user to click it.
});
}
}
this gave me this error:
http://127.0.0.1/project/public/dropzone/store 419 (unknown status)
myController:
public function dropzone()
{
return view('dropzone-view');
}
/**
* Image Upload Code
*
* #return void
*/
public function dropzoneStore(Request $request)
{
$dir = public_path().'/upload/';
$files = $request->file('file');
foreach($files as $file){
$fileName = $file->getClientOriginalName();
$file->move($dir, $fileName);
}
}
routes: web.php
Route::get('dropzone', 'HomeController#dropzone');
Route::post('dropzone/store', ['as'=>'dropzone.store','uses'=>'HomeController#dropzoneStore']);
Laravel returns a 419 response when there is a token mismatch problem. The code you've shown POSTs files to your server, but does not pass a _token with the request. The web middleware, which is applied by default, will do token verification, and since there is no token, that will fail and throw a 419.
You can probably see this yourself if you look in your browser's devtools, click the network tab, click the POST request where the file is uploaded, and click the Preview or Response tabs.
So you need to pass a _token along with the request. There are many ways to do that, but the simplest is probably what is described in the docs:
Add the token to your <head>
<meta name="csrf-token" content="{{ csrf_token() }}">
Automatically pass it with every AJAX request:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
I am using Laravel 5.3 and vue.js 2.0,
And I use axios (https://github.com/mzabriskie/axios) to send ajax requests,
I follow the docs to set the TOKEN like this:
<script>
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; //The error is at this line.
new Vue({
el: "#app",
data: function () {
return {
items: []
}
},
mounted: function () {
this.$nextTick(function () {
axios.get('/articles').then(function (response) {
response.data.forEach(function (item) {
item.selected = false;
});
this.items = response.data;
}).catch(function (error) {
console.log(error);
});
});
}
});
</script>
the error in console is like this:
Uncaught ReferenceError: AUTH_TOKEN is not defined
What should I do?
have you set AUTH_TOKEN on the window? If not window.AUTH_TOKEN will naturally not be defined.
A common set up in the head of a laravel app is:
<script>
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
]); ?>
</script>
This would therefore set the csrf token. I wouldn't imagine this is how you'll be setting an Auth token so you'll probably just need to look into why you are calling window.AUTH_TOKEN
In terms of how you generate your token that is dependant on what type you require but once you have it you may want to look instead at vuex for storing it. Doing so will allow you access to it throughout your app, without having to store anything on the window.
it should be
axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
and you can remove the
<script>
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
]); ?>
</script>
part
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
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.