VueJS/Laravel - vue-resource allways gives status 419 on post request - laravel

i'm trying to get my post request running in vue.
I'm using vue-resource to do post/get requests. Get method is working. Post is not.
I used the vue-resource "get" for a pagination on my laravel program and it worked perfect.
Now I need to pass some data via post to my server, but this doesn't really work.
My app.js:
// require('./bootstrap');
window.Vue = require('vue');
import VueResource from 'vue-resource';
Vue.use(VueResource);
Vue.component('example-component', require('./components/ExampleComponent.vue'));
Vue.component('prices', require('./components/prices.vue'));
const app = new Vue({
el: '#app'
});
The important part of my component, where i'm trying to do the post request:
saveSellAndBuy: function () {
Vue.http.post('/dashboard/savePricingData', {
buyAP: this.buyAP,
sellAP: this.sellAP,
tradeID: this.currentEditedKey
}).then(function (data) {
console.log(data);
});
}
What I get:
app.js:13790 POST http://unicorn.com/dashboard/savePricingData 419 (unknown status)
Some exceptions of laravel with no message
exception: "Symfony\Component\HttpKernel\Exception\HttpException"
file: "/var/www/unicorn.de/htdocs/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php"
line: 203
message: ""
And yeah.. I have no clue anymore. Other people with the same or related problem said I need this in my head:
<meta name="csrf-token" content="{{ csrf_token() }}">
and this at the end ( this gets rendered after the vue instance )
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
Of course I had those at the right place. I also tried to put this snipped here:
Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('#token').getAttribute('content');
At the end of my app.js file and it did not worked out for me. If I put this code over the const app and not at the end, my whole vueJS is not running anymore.
And here a picture that shows, that I do have the right cookies like XHR
Okay, I've found a way. I haven't thought that this will work. In the Laravel VerifyCsrfToken.php is a :
protected $except = [
'/dashboard/saveTradingData'
];
Where I can add URIs that should be excluded from CSRF verification.
But I don't really like this solution..

You can set the headers of any requests going out for vue-resource using interceptors:
Vue.http.interceptors.push((request, next) => {
const token = document.querySelector('#token').getAttribute('content')
if (token) {
request.headers.set('X-CSRF-TOKEN', token)
}
next()
})

Related

How do I send CSRFToken in my axios requests using Nuxt and Django on the backend?

I'm using Django Rest as a backend api, and each API call requires a CSRF Token in the headers. In my "Applications" tab in Developer Tools, I clearly have a "csrftoken" value and I somehow need to extract that with each subsequent POST request that my Nuxt application does (using Nuxt/Axios)
My settings.py looks like this:
CORS_ORIGIN_WHITELIST = (
"http://localhost:3000",
"http://127.0.0.1:3000",
)
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
CORS_EXPOSE_HEADERS = ['Content-Type', 'X-CSRFToken']
CORS_ALLOW_CREDENTIALS = True
CSRF_COOKIE_SAMESITE = "Lax"
SESSION_COOKIE_SAMESITE = "Lax"
CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_HTTPONLY = True
I have tried using js-cookies with Cookies.get("csrftoken") which just returns undefined. Is the cookie not accessible because it's set to HTTPONLY`?
What is the recommended step here? Should I create a view in my django backend to generate a CSRF Token, and then before making each request on the frontend, I call this view in my Django app to fetch the token?
E.g
def get_csrf(request):
response = JsonResponse({"detail": "CSRF cookie set"})
response["X-CSRFToken"] = get_token(request)
return response
Not sure how to proceed..
My Nuxt/Axios requests looks something like this:
const response =
await this.$axios.$post("/api/portfolios/", stockData,
{ headers: { "X-CSRFToken": /* Need some value here. */ }
});
I can however get the cookie using nuxtServerInit in my Nuxt Store:
async nuxtServerInit({commit}) {
console.log(this.$cookies.get("csrftoken")) // this works, can store it in some state
},
I can store the value from nuxtServerInit in a Nuxt store. However, whenever I logout, how do I make sure to extract the new csrftoken from the browser? The nuxtServerInit part above only works if I do a page reload, which isn't ideal.
Appreciate any guidance I can get.
Setup axios with default xsrfHeaderName and xsrfCookieName values via nuxt plugin.
When configured, axios will include in request your csrf header with cookie value if it's present in cookies.
in nuxt.config.js include your new plugin
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
'~/plugins/axios',
]
create plugins/axios.js
There is the option to declare as global default config, or for a nuxt instance.
// content of plugins/axios.js
/*
// This is a global config declaration that works on any axios instance,
// meaning that if you just import axios from 'axios' in any place, you will get those.
// This will also work on the axios instance that nuxt creates and injects.
import axios from 'axios'
axios.defaults.xsrfHeaderName = 'x-csrftoken'
axios.defaults.xsrfCookieName = 'csrftoken'
*/
export default function ({ $axios }) {
// This is a nuxt specific instance config, this will work in
// everyplace where nuxt inject axios, like Vue components, and store
$axios.defaults.xsrfHeaderName = 'x-csrftoken'
$axios.defaults.xsrfCookieName = 'csrftoken'
}

Where to add axios interceptors code in vue js

I am using vue js as frontend with laravel. I am using laravel passport for auth, now i wants to show some error message once received 401 unauthentic error message that mostly occurs when my token expired. so to do this i am using axios interceptors my code is like
axios.interceptors.response.use(function (response) {
return response
}, function (error) {
// const { config, response: { status } } = error
const { config, response } = error
const originalRequest = config
if (response && response.status === 401) {
//notication or redirection
this.$vs.notify({
title: 'Error',
text: response.data['message'],
iconPack: 'feather',
icon: 'icon-check-circle',
color: 'danger'
})
}
return Promise.reject(error)
})
Now Question is that where i put this code in vue js so that it call after every request & so an error message shown & redirect to login once get 401 unauthorized..
Any Suggestion from anyone.
Thanks in advance!!
app.js or add them to separate file and include in app.js. There is post about this https://medium.com/#yaob/how-to-globally-use-axios-instance-and-interceptors-e28f351bb794

Laravel VueJS axios interceptor accessing the vue application

I've got what's basically the default Vue JS scaffolding that comes with Laravel.
// app.js
require('./bootstrap');
window.Vue = require('vue');
const app = new Vue({
el: '#app',
methods: {
refreshToken: function() {
console.log('refreshing the token');
}
}
});
// bootstrap.js
window._ = require('lodash');
window.Popper = require('popper.js').default;
try {
window.$ = window.jQuery = require('jquery');
require('bootstrap');
} catch (e) {}
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
This should be familiar to anyone who has used Vue JS with Laravel before.
Now i've tried to add an axios interceptor to handle errors, i've done this below the X-Requested-With header in bootstrap.js
window.axios.interceptors.response.use(
response => response,
error => {
// Show the user a 500 error
if (status >= 500) {
console.log({500:error});
}
// Handle Session Timeouts
if (status === 401) {
console.log({401:error});
app.refreshToken();
}
// Handle Forbidden
if (status === 403) {
console.log({403:error});
}
return Promise.reject(error)
}
);
The console.log() instances work fine to verify that it is working.
However app.refreshToken() does not work (and does not give an error either?).
I'm not that surprised since I haven't imported it or anything.
But i've tried this at the top of bootstrap.js: import app from './app.js';
And npm run watch now throws a warning:
"export 'default' (imported as 'app') was not found in './app.js'
I modified app.js to change const app to be export const app but this didn't make any difference.
I'm pretty sure I am just missing some basic understanding of importing and exporting within es6 but unfortunately I can't find anything on Google that will explain it.
Most of my Googling of how to setup this axios interceptor to handle errors has come up with examples using vuex. I really don't want to bring in vuex just to resolve this as I don't want to touch it until i'm sure it's necessary for my particular app and it definitely seems overkill just to be able to follow a tutorial.
How can I call my app.refreshToken() method or access my vue instance within the axios interceptor?
After
require('./bootstrap');
window.Vue = require('vue');
const app = new Vue({
el: '#app',
methods: {
refreshToken: function() {
console.log('refreshing the token');
}
}
});
Add what the error says it's missing:
"export 'default' (imported as 'app') was not found in './app.js'
Just add this:
export default app;
That might solve the compilation problem, as for the call to the function, i have not tested it yet... came with a very similar problem 15 minutes ago..

Django CSRF Token Missing Only in Production

I am getting a missing CSRF_Token error that only occurs in production mode on my server. However everything works great when I am running it from my computer terminal using the runserver command. I've read through many of the other questions pertaining to this with no luck. It seems that my case is slightly different than others, since it works locally but not in production.
I get the error when submitting an Ajax form that submits to the "submit" in views.py. Does anybody know what could be causing this? Also, looking at my cookies in Production mode, the CSRF_Token is not even there to begin with. Locally it is. Thanks for any help.
Here is my views.py
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return render(request, 'index.html')
def submit(request):
#Receive Request
inputone = request.POST['randominfo']
inputtwo = request.POST['randominfo2']
#Some more code here that setups response.
#Deleted since Im posting to StackOverflow
return response
Code Pertaining to the Ajax Submit
$(function () {
$.ajaxSetup({
headers: { "X-CSRFToken": getCookie("csrftoken") }
});
});
function getCookie(c_name)
{
if (document.cookie.length > 0)
{
c_start = document.cookie.indexOf(c_name + "=");
if (c_start != -1)
{
c_start = c_start + c_name.length + 1;
c_end = document.cookie.indexOf(";", c_start);
if (c_end == -1) c_end = document.cookie.length;
return unescape(document.cookie.substring(c_start,c_end));
}
}
return "";
}
function submitAjax(event){
$.ajax({
type:'POST',
url:'/submit/',
data:{
randominfo:document.getElementById('Random').innerHTML,
randominfo2:document.getElementById('Random2').innerHTML,
},
dateType: 'json',
success:function() {
# Url here
}
})
};
Solution that fixed this problem.
Adding "from django.views.decorators.csrf import ensure_csrf_cookie" in views.py and then "#ensure_csrf_cookie" above the view that returns the html file that contained the ajax form
The error ocurs because you are not setting the csrf token, to prevent this we have to check some details
First of all, you have to set the csrf token to your form, in your html you have to set some as follow:
<form id="id" name="form">
{% csrf_token %}
<!-- Form body here -->
</form>
Second the approach to set the csrf cookie to your request header is ok, i only suggest that instead you set your data field one by one, use method serialize of jquery
data: $("#your-form-id").serialize()
I would like to recommend you to read this post about ajax request with django that is very helpful
There are 2 things you can do:
1.) Submit a CSRF token in your ajax call. You have to use a getCookie() javascript function to get it. Luckily the django documentation has some code you can copy and paste.
javascript
$.ajax({
type:'POST',
url:'/submit/',
data:{
randominfo:document.getElementById('Random').innerHTML,
randominfo2:document.getElementById('Random2').innerHTML,
'csrfmiddlewaretoken': getCookie('csrftoken'), // add this
...
2.) Disable csrf for your /submit view. You can do this with a decorator. Note that this is less secure so make sure there's no confidential data.
views.py:
from django.views.decorators.csrf import csrf_exempt
...
#csrf_exempt
def your_submit_view(request):
#view code

this.$http vueJs not set

I'm playing with vueJS and trying to grab some data from an ajax request.
Heres my code:
new Vue({
el: '#recipeList',
ready: function () {
this.fetchRecipes();
},
methods: {
fetchRecipes: function () {
this.$http.get('/recipes/ajax', function (recipes) {
this.$set('recipes') = recipes;
});
}
}})
The html code is fine, I doubt you need to see that.
The documentation says that this is how you do a ajax request, however the $http object does not appear to be set.
Here is the console error I am receiving:
TypeError: undefined is not an object (evaluating 'this.$http.get')
fetchRecipesapp.js:10
(anonymous function)vue.js:307
readyapp.js:5
_callHookvue.js:8197
readyvue.js:10169
$mountvue.js:10155
_initvue.js:8054
Vuevue.js:80
global codeapp.js:1
app.js:10
$http.get is for Vue Resource. Make sure you are pulling that in properly. i.e., add vue-resource to your package.json, then npm install, then...
var Vue = require('vue');
Vue.use(require('vue-resource'));
Also, make sure your root path is set up properly.
Vue.http.options.root = '/your-root-path';
Hope it helps! :-)

Resources