I'm writing a webservice API (in laravel 4.2).
For some reason, the routing to one of my controllers is selectively failing based on HTTP method.
My routes.php looks like:
Route::group(array('prefix' => 'v2'),
function()
{
Route::resource('foo', 'FooController',
[ 'except' => ['edit', 'create'] ]
);
Route::resource('foo.bar', 'FooBarController',
[ 'except' => ['show', 'edit', 'create'] ]
);
}
);
So, when I try any of GET / POST / PUT / PATCH / DELETE methods for the
project.dev/v2/foo or project.dev/v2/foo/1234 urls, everything works perfectly.
But, for some reason, only GET and POST work for project.dev/v2/foo/1234/bar. The other methods just throw a 405 (MethodNotAllowedHttpException).
(fyi, I am issuing requests via the Advanced Rest Client Chrome extension.)
What's going on?
What am I missing?
Solved!
The answer can be found by running php artisan routes.
That showed me that DELETE and PUT/PATCH expect (require) a bar ID.
I happened to be neglecting that because there can only be one of this particular type of "bar". The easy fix it to simply add it to my URL's regardless, like project.dev/v2/foo/1234/bar/5678.
For the ones who are using Laravel versions > 4.2 use this :
php artisan route:list
This will give the list of routes set in your application. Check if routes for PUT and DELETE are allowed in your routes or not.
405 error is mostly because there is no route for these methods.
I don't know about older Laravel versions. But I use Laravel since 5.2 and it is necessary to include a hidden method input when using put, patch or delete.
Ex:
<input type="hidden" name="_method" value="PUT">
Check https://laravel.com/docs/5.6/routing#form-method-spoofing
Just add a hidden input field to your form
<input type="hidden" name="_method" value="PUT">
And keep form method as post
<form method="post" action="{{action('')}}">
If you want to use the method PUT in submit form you mast to see this link
https://laravel.com/docs/5.6/routing#form-method-spoofing
But if you use ajax in your project you mast to do anything like this:
<form>
#method('PUT')
// your_element
on your script add:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: {{ route('your_route', ':id') }},
type: 'POST',
data: data,
dataType: 'json',
cache: false,
}).done(function(data,status){
// anything
}).fail(function(){
// anything
});
Related
I have the following group of GET routes on Laravel:
Route::get('/location/get', 'Ajax#getProducts');
Route::get('/products/get', 'Ajax#getProducts');
Route::get('/schedule/get', 'Ajax#getProducts');
I want to protect those routes with the automatically generated CSRF token from Laravel.
I have read some workarounds about overriding method: VerifyCsrfToken#isReading(...), but I'm not too much convinced about that.
Then I'm looking for a more elegant solution.
Thanks!
CSRF is not protecting your data. More info: https://security.stackexchange.com/a/115808
If you has no reason for using GET method with CSRF, just use POST with default csrf middleware group:
Route::group(['before' => 'csrf'], function() {
// your ::post routes
});
Anyway, you can try to create VerifyCsrfTokenAll middleware, and use csrf_get key from this answer: https://stackoverflow.com/a/41656322/2453148
and then wrap your routes in this group:
Route::group(['before' => 'csrf_get'], function() {
// your routes
});
Best thing I would adhere to is including the #csrf with your blade form.
<form action=“{{ your route name }}” method=“GET”> #csrf </form>
I am writting APIs for android/ios using Laravel 5.4. My simple webservice signUp which is working perfectly on localhost not working on live server and giving
MethodNotAllowedHttpException on POST methods
GET call works perfect .
Route code
Route::post('/signUp',['uses'=>'API_UserController#userSignUp']);
Attached is screen shot link of my postman.
https://i.stack.imgur.com/060IF.png
here is quick example of flow try this
<form action="{{url('v1/userSignUp')}}" class="validation" method="post"
accept-charset="utf-8">
{{ csrf_field() }}
<div>
// your required form field
<input type="submit" value="Add Category" class="btn btn-primary" />
</div>
</form>
and in your route add this
Route::get('/signUp', function () {
return view('yourviewpagename');
});
Route::post('/signUp','API_UserController#userSignUp');
and in your API_UserController
public function userSignUp()
{
dd(request->all());
}
#Mujeeb Ur Rehman Post method is use to send data and get method is use to access data in view or just to render view.
eg:-route:post('/home',xxController#xx);
route:get('/home1',xxController#xx);
error which you are getting is because suppose if you url it like this localhost/xx/home your framework think to access data or post data framework get confuse in this
just use like this
Route::group(['prefix' => 'v1'], function () {
Route::post('/signUp','API_UserController#userSignUp');
});
when you hit via postman tour URL is http://your_domain/api/v1/signUp so just add a prefix it will automatically add with your URL. in route group u can also use many other things like namespace, middleware etc. Example :
Route::group(['namespace' => 'any_depend_on_your_project_structure', 'middleware' => 'any_middleware', 'prefix' => 'v1'], function() {
// your routes
});
I'm sending an ajax post request, and with Laravel it seems that is done by creating a post route for it. I've set it up so a csrf token is put in the header automaticaly for every ajax request using ajaxSetup. I'm attempting to then catch that header on the backend and verify the tokens match.
In my web routes (which automatically use the web middleware), this returns as expected:
Route::get('/test', function() {
return csrf_token();
});
However, when I post to a route via AJAX, like either of the below ways:
Attempt 1:
Route::post('/test', 'AjaxController#test');
In the AjaxController construct, followed by an alert in the view:
var_dump(csrf_token().',hi'); die;
Response: ',hi' (csrf_token was null).
Attempt 2:
Route::post('/test', ['test' => csrf_token().',hi', 'uses' => 'AjaxController#test']);
$test = $request->route()->getAction()['test'];
var_dump($test); die;
Response: ',hi' (csrf_token was null).
What I seem to be running into is, with get requests csrf_token() is populated, on my post request, it is not.
Any ideas?
check your route group it must apply the web middleware as
Route::group(['middleware' => 'web'], function () {
Route::get('/test', function() {
return csrf_token();
//or return $request->session()->token();
});
});
Finally figured this out.
CSRF can indeed be checked on an ajax post request. I wanted to make sure someone on their own site isn't hitting my ajax endpoint with any success of doing anything, especially for another user.
However, I ran into a Laravel order of operations issue, with the way Laravel sets up the session. I was trying to call a validation method (within in the same class) in the constructor, where I validated for CSRF and verified the requesting user all in one place. I wanted to do this so that any time someone hits this class, I didn't have to call the verification in each public method in the class, I'd only have to call it once.
However, csrf_token(), and the request session in general, is not available to me yet in my construct. It is, however, available to me in the method within the controller class that is called in the route.
For example, given the following route:
Route::post('/test', 'AjaxController#test');
If I injected Request into the construct and then tried to reference anything in the session (in the construct), or get the value of csrf_token(), it will throw an error, because Laravel hasn't set that stuff up yet. But if I reference either of those things in the test method, it'll be there and available just fine.
A bit of a weird Laravel order of operations issue.
csrf protections are managed by Laravel Forms. It won't be available when dealing with APIs.
You should have a look at how middlewares are used in Laravel
https://laravel.com/docs/5.4/middleware
Think using API middleware for your APIs ;)
If you run this command php artisan make:auth documented here https://laravel.com/docs/5.4/authentication#authentication-quickstart when going to resources/views/layouts/app.blade.php you'll see this:
<meta name="csrf-token" content="{{ csrf_token() }}">
And in app.js
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN':$('meta[name="csrf-token"]').attr('content')
}
});
In 5.3 there was this cool feature which looks as though it has since been removed in 5.4.
<script>
window.Laravel = <?php echo json_encode([
'csrfToken' => csrf_token(),
]); ?>
</script>
So what you need to do is add the csrf field to every request. Do the first 2 code snippets and you'll be fine. The 3rd I believe is probably for Vue.
Answer to your question: no, no, no and no. CSRF tokens I wouldn't believe are generated in POST requests, it's a Cross site Reference token, not an authentication token. If you're looking for something like authentication token refreshing then checkout JWT although the packages for JWT for laravel are a bit unfinished at the moment; with a little work you can get them working.
https://github.com/tymondesigns/jwt-auth 1.0.*#dev is pretty good. You can then use their refresh middleware to generate new tokens on request but this is quite advanced and unless it's for authentication then I wouldn't bother really.
I believe Dingo (another work in progress I believe) https://github.com/dingo/api uses the above package
Anything else let me know!
There is a form in my view, from where, on clicking submit, data is taken to ajax script which is supposed to invoke the controllers specified in the post routes in routes.php. The controllers are expected to process the received data and throw the result back to the view. Why is this error occurring immediately after submitting the form and things aren't working as expected>
Check your routes.php file. Make sure that the method your using corresponds with what you have allowed.
Here is the laravel documenation for routes
For example, if your request is a GET request, the call should look like this in the routes file:
Route::get('/test-get-url', function () {
// Matches The "/test-get-url" URL using a GET method
});
And for post
Route::post('/test-post-url', function () {
// Matches The "/test-post-url" URL using a POST method
});
Go to terminal/cmd..whichever you using and type
php artisan route:list
this will list all your routes and check at what route your is being submitted.Note the corresponding method to be used in the Method column and use that method while submitting form.I'm assuming it's PUT method(which is most likely).Ex--
Use method attribute if you're using simple HTML code like--
<form action="{{route='..'}}" method="PUT">
or if you're using form helper then use--
{!! Form::open($post, ['route' => ['..'], 'method' => 'PUT']) !!}
Go to your route.php file and check
Route::get('someroute',['uses'=>'somecontroller#function_get','as'=>'some_get']);
Route::post('someroute',['uses'=>'somecontroller#funtion_post','as'=>'some_post']);
make sure if your are using (as) in you routes its different and also where you use your ajax you properly define your route where you want to post your form data and it's type is same as you mention in routes and one more thing check you properly use (;) in your code
hope this will help you fell free to ask your query
Im trying to do a POST request with jQuery but im getting a error 405 (Method Not Allowed), Im working with Laravel 5
THis is my code:
jQuery
<script type="text/javascript">
$(document).ready(function () {
$('.delete').click(function (e){
e.preventDefault();
var row = $(this).parents('tr');
var id = row.data('id');
var form = $('#formDelete');
var url = form.attr('action').replace(':USER_ID', id);
var data = form.serialize();
$.post(url, data, function (result){
alert(result);
});
});
});
</script>
HTML
{!! Form::open(['route' => ['companiesDelete', ':USER_ID'], 'method' =>'DELETE', 'id' => 'formDelete']) !!}
{!!Form::close() !!}
Controller
public function delete($id, \Request $request){
return $id;
}
The Jquery error is http://localhost/laravel5.1/public/empresas/eliminar/5 405 (Method Not Allowed).
The url value is
http://localhost/laravel5.1/public/empresas/eliminar/5
and the data value is
_method=DELETE&_token=pCETpf1jDT1rY615o62W0UK7hs3UnTNm1t0vmIRZ.
If i change to $.get request it works fine, but i want to do a post request.
Anyone could help me?
Thanks.
EDIT!!
Route
Route::post('empresas/eliminar/{id}', ['as' => 'companiesDelete', 'uses' => 'CompaniesController#delete']);
The methodNotAllowed exception indicates that a route doesn't exist for the HTTP method you are requesting.
Your form is set up to make a DELETE request, so your route needs to use Route::delete() to receive this.
Route::delete('empresas/eliminar/{id}', [
'as' => 'companiesDelete',
'uses' => 'CompaniesController#delete'
]);
Your routes.php file needs to be setup correctly.
What I am assuming your current setup is like:
Route::post('/empresas/eliminar/{id}','CompanyController#companiesDelete');
or something. Define a route for the delete method instead.
Route::delete('/empresas/eliminar/{id}','CompanyController#companiesDelete');
Now if you are using a Route resource, the default route name to be used for the 'DELETE' method is .destroy. Define your delete logic in that function instead.
In my case the route in my router was:
Route::post('/new-order', 'Api\OrderController#initiateOrder')->name('newOrder');
and from the client app I was posting the request to:
https://my-domain/api/new-order/
So, because of the trailing slash I got a 405. Hope it helps someone
If you didn't have such an error during development and it props up only in production try
php artisan route:list to see if the route exists.
If it doesn't try
php artisan route:clear to clear your cache.
That worked for me.
This might help someone so I'll put my inputs here as well.
I've encountered the same (or similar) problem. Apparently, the problem was the POST request was blocked by Modsec by the following rules: 350147, 340147, 340148, 350148
After blocking the request, I was redirected to the same endpoint but as a GET request of course and thus the 405.
I whitelisted those rules and voila, the 405 error was gone.
Hope this helps someone.
If you're using the resource routes, then in the HTML body of the form, you can use method_field helper like this:
<form>
{{ csrf_field() }}
{{ method_field('PUT') }}
<!-- ... -->
</form>
It will create hidden form input with method type, that is correctly interpereted by Laravel 5.5+.
Since Laravel 5.6 you can use following Blade directives in the templates:
<form>
#method('put')
#csrf
<!-- ... -->
</form>
Hope this might help someone in the future.
When use method delete in form then must have to set route delete
Route::delete("empresas/eliminar/{id}", "CompaniesController#delete");
I solved that issue by running php artisan route:cache which cleared the cache and it's start working.
For Laravel 7 +, just in case you run into this, you should check if the route exists using
php artisan route:list
if it exists then you need to cache your routes
php artisan route:cache