I'm trying to build and application on Laravel, VueJS and inertiajs.
I'm using maatwebsite/excel to export my data into excel format.
I've a vue component which has a normal HTML form
home.vue
<form action="/project-profile" target="_blank" method="POST" enctype="multipart/form-data">
<input type="hidden" name="_token" :value="csrf.content" />
<input type="hidden" name="slug" :value="JSON.stringify(generalDetails.slug)" />
<button class="font-medium tracking-wide">Download Profile</button>
</form>
And on mounted method I'm just placing my csrf token.
mounted() {
this.csrf = document.head.querySelector('meta[name="csrf-token"]');
}
In Laravel part I made a route in web.php file
Route::post('project-profile','ProjectProfileExportController#ProjectProfile');
Whenever I try to export or submit the form, I get page expired error, I followed few guide and it says there is issue with csrf_token but while inspecting the form I can see token is placed appropriately.
I tried doing the same by making this as api, api.php:
Route::post('project-profile', 'ProjectProfileExportController#ProjectProfile');
But this thing also not work as expected.
Screenshot of page expired screen
Screenshot of inspect form element
Any better approach is welcome. Thanks.
Creator of Inertia.js here.
So, we recommend not manually sending the csrf token on each request like this.
A better approach is to use the CSRF functionality already built into axios for this. Axios is the HTTP library that Inertia uses under the hood.
Axios automatically checks for the existence of an XSRF-TOKEN cookie. If it's present, it will then include the token in an X-XSRF-TOKEN header for any requests it makes.
The easiest way to implement this is using server-side middleware. Simply include the XSRF-TOKEN cookie on each response, and then verify the token using the X-XSRF-TOKEN header sent in the requests from axios.
Some frameworks, such as Laravel, do this automatically, meaning there is no configuration required. So, I'd recommend removing the csrf-token meta tag from your template, and removing the _token from your requests. That should take care of your issues.
That all said, keep in mind that you will not be able to download an Excel file from an Inertia request. All Inertia requests MUST return a valid Inertia response. You can use window.open for this. Something like this:
window.open(`/url/to/excel/download?slug=${generalDetails.}`, '_blank')
Related
I have a function in my controller that is used to store data. I am recreating my front end using Vue.js. As of now, I removed the current Laravel {{ Form: }} with Vue.js. Can I use same synchronous route without api to post the data? APIs are not ready and I cannot wait to validate my forms
Sure you can, all you need to do is to be aware that HTML does not have methods other than GET and POST. So, if you have PUT, DELETE and others, you're going to have to use the _method param trick.So, for example, when using the PUT http verb, you should create your form something like this:
<form method='POST'>
yourfields...
<input type="hidden" name="_method" value="PUT">
</form>
Other than that, it's pretty much calling the correct endpoints from your Vue application.
Laravel forms need csrf to work
If i make spa, single page application, with vue+laravel so that my laravel template contains only empty html and body,
and user doesn't actually refresh the page at all during many hours of working with app,
(page does not refresh because everything is with ajax)
How do I get to keep the login session alive ?
How do I get the csrf to work ? Or can i disable it ?
The application does nothing without login first.
If you are using axios with Vue2 for your ajax requests csrf is already available in bootstrap.js, you could see there this line
let token = document.head.querySelector('meta[name="csrf-token"]');
If you want to insist for your ajax only, then you would have put this line in your mounted hook.
mounted() {
this.csrfToken = document.querySelector('meta[name="csrf-token"]').content
},
this csrfToken should be attaached in your forms like this one
<form :method="method.toUpperCase() == 'GET' ? 'GET' : 'POST'">
<input-hidden :value="csrfToken" name="_token"/>
<input-hidden
v-if="['GET', 'POST'].indexOf(method.toUpperCase()) === -1"
:value="method"
name="_method"
/>
<!--
This hidden submit button accomplishes 2 things:
1: Allows the user to hit "enter" while an input field is focused to submit the form.
2: Allows a mobile user to hit "Go" in the on-screen keyboard to submit the form.
-->
<input type="submit" class="absolute invisible z-0">
<slot/>
</form>
for good example of it. check this out csrf token
Note: Please don't disable csrf token cause it's only your way to secure your requests to the server.
I have a problem in Laravel . when over and over submit Form with post method and somtimes I get error and see expire error that related to CSRF
anybody knows how can I manage this error that display not in site and instead of redirect to any page else ?
Laravel makes it easy to protect your application from cross-site request forgery (CSRF).
Just add #csrf blade directive inside the form to avoid getting csrf token error.
<form method="POST" action="/profile">
#csrf
...
</form>
The directive puts something like this
<input type="hidden" name="_token" value="CzK6peomC6Pnnqdm4NsxpdGSH6v1evDnbN12oL" >
Read more about it in the laravel documentation here https://laravel.com/docs/5.6/csrf
Regarding the expiration of the token I think you might want to handle the error this way https://gist.github.com/jrmadsen67/bd0f9ad0ef1ed6bb594e
Also, there's a package which helps the forms keep awake.
https://github.com/GeneaLabs/laravel-caffeine
I hope that helps.
Laravel 5 using Blades templates, it's easy.
Add csrf toke in your blade file
{{ csrf_token() }}
If you are using Laravel 5.6 then you need to add something like this in your code of the form
#csrf
Check in detail about: CSRF Laravel
My Flask app is AJAX-heavy, but does not use any cookies. Is CSRF still a threat or is it safe to deploy the app as of now?
I have already looked at this SO question but my situation is slightly different, since I do not have to worry about user's credentials.
I tried an AJAX call from Chrome DevTools (using $.ajax()) to my server which was running on localhost (Flask development server) and I got an error saying
XMLHttpRequest cannot load http://localhost:5000/_ajax. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'chrome://newtab' is therefore not allowed access.
Does this mean I am safe, or is it possible that a hacker could circumvent this and still make AJAX calls to my server?
CSRF isn't just protection against CORS AJAX. I could make a form on my site, and set the action to http://yoursite.com/account/delete. If a user submits my form, without CSRF on your site, the action would succeed. Or if you have things change on GET requests (shouldn't do that anyway), I could add this to my site:
<img src="http://yoursite.com/account/delete" />
and the action would happen when my page loads.
Check out Flask-WTF or this snippet: http://flask.pocoo.org/snippets/3/
EDIT
From your comment:
Change the action of that page to a POST, and have it be accessed through a form instead of a link. If your link was:
<a href="{{ url_for('my_page') }}">Click Here</>
Your form could be (using Flask-WTF, which you would need):
<form action="{{ url_for('my_page') }}" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="submit" value="Click Here" />
</form>
Im trying to download a pdf with ajax request yet the response from that request ignores my "Content-Type:application/pdf" header.
The ajax request
return Superagent.post(url, data).use(this._addDefaults.bind(this));
The symfony response
return new BinaryFileResponse($target);
Workaround
open in new tab and put a direct url for the file.
I think this is similar to a problem I've encountered in the past. Issue is that browsers don't open responses to POST ajax requests by default. I ended up resorting to the automatic form posting instead. In the HTML:
<form method="post" action="http://handler1.ashx" target="_blank">
<input type="hidden" id="data" name="data" value="post_body_stuff"/>
<button id="pdfsubmit" type="submit" value="Submit">Export to PDF</button>
</form>
You can use javascript to put all the data you want to POST as the value on the hidden input field instead of post_body_stuff. This way, when the content comes back the browser will try to open or save it as a file rather than read it as response text.