Laravel 5 global middleware not working - php

I have a route group in my routes.php file with the middleware specified like so:
Route::group(['prefix' => 'api', 'middleware' => 'api'], function() {
Route::post('oauth/access_token', function() {
return Response::json(Authorizer::issueAccessToken());
});
}
I am using the Lucadegasperi Oauth2 Server addon. For its setup, I had to enter the following LucaDegasperi item in the $middleware array of the Kernel.php file (Kernel class):
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\LucaDegasperi\OAuth2Server\Middleware\OAuthExceptionHandlerMiddleware::class,
];
The $middlewareGroups array of the same class is as follows:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
What the OAuthExceptionHandlerMiddleware does is that it formats exceptions to JSON responses. Now when I apply the 'middleware' => 'api' in the route group as shown, the global middlewares dont work. I can say this because the HTML error page shows when exceptions occur. However, when I omit the 'middleware' => 'api' in the route group, the global middlewares work and I get JSON responses for the errors.
How do I get past this?

The reason for this is due to changes with how Laravel handles exceptions in Middleware from 5.2.7 onwards, as documented in this ticket I raised. To fix this you need to alter your Exception handler (as explained in the issue) or await the latest patch from the package.
I've commmitted a fix to the repository which fixes the issue of the changes made to Laravel 5.2, however this has not yet been merged.

Did you remember to add Authorizer to aliases array?
'Authorizer' => LucaDegasperi\OAuth2Server\Facades\Authorizer::class,
Because you're using it in:
Route::post('oauth/access_token', function() {
return Response::json(Authorizer::issueAccessToken());
});

Related

Laravel - access session variables in API

I have a simple application and I want to be able to change language.
In my main controller I have:
session(['applocale' => 'en']);
$request->session()->put('applocale','en');
I know that these two lines are the same but I want to be sure that they both does not work.
Then I have API method:
public function switchLang(Request $request, $lang)
{
error_log("Current language is: " . session('applocale'));
error_log("Current language is: " . $request->session()->get('applocale'));
}
And here error_log shows nothing.
I'm following this thread: Laravel 5.3 - How to add Sessions to API without CSRF?
And in Debugbar I can see that my API function has hit middleware 'sessions' but session variables are not there.
That's how it's look like my 'seasons' middleware:
'sessions' => [
\Illuminate\Session\Middleware\StartSession::class,
]
It actually hits both 'api' and 'sessions' middleware.
Any ideas what I'm doing wrong?
This works for me (Laravel-5.7 ).
Firstly change the api middleware group to -
'api' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
'throttle:60,1',
'bindings',
],
in App\http\kernel.php .
Reference here.

Laravel 5.5 empty object

Good afternoon guys, I'm having an issue I don't know if you have the same trouble, I upgrade my Laravel project and now all routes like this
Route::get('detail/client/{client}', "controller#method")
are breaking everything because the object instanced in the controller comes empty...
public function detail(FileRequest $request, Client $client){
dd($client) // empty object
}
If someone can help me with this please. If I remove the Client model and make the dd then return the ID of the object i.e "594"
You haven't written base Laravel version you are upgrading from, but I think it might have something in common with \Illuminate\Routing\Middleware\SubstituteBindings::class middleware.
Make sure you have it in middlwareGroups like this:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class, // <- this is the line you should have
],
'api' => [
'throttle:60,1',
'bindings',
],
];
in app/Http/Kernel.php file
and also make sure the routes you have problem are in web middleware group.

Building a call API project with laravel

I would like to build a call API laravel project, separate the front-end and back-end, but how?
All the API are writing in the routes/api.php, but the job that return a view still live in routes/web.php ,
is that normal ? if not, what should I do ?
The code like ...
routes/web.php:
Route::get('/book/{id}',function(){ return view('book.show')->with('id',$id) ;});
show.blade.php:
...
$(function(){
$.ajax{
url: 'api/book/{{ $id }}',
....
}
});
...
routes/api.php:
//return the book data that id = {id}
Route::get('/book/{id}','BookController#show');
You are using it correctly.
One of the benefits of separating web and api routes is you have more granular control over applying middlewares.
Take a look at app/Kernel.php file:
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
As #angad-dubey mentioned its good practise to separate them out so that the web deals with the front end and the api routes for ... Api calls.
I tend to separate mine further by adding an admin.php within the routes folder, so that my backend routes are also separated, Thus you don't have one file with a long list of routes to search through, and this way as shown above you can append different middleware to them and not to the others, which could cause issues in the long term

Why is the csrf token checked when i use api middelware

i am using laravel 5.2 whit the predefined middelwares 'api' and 'web'. in the kernel file its stated that web would use quite some while api only checks throttle:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
in my routes i grouped the api routes and applied only 'api'
Route::group(array('prefix' => 'api', 'middleware' => ['api']), function(){
Route::post('test', 'TestController#testfunction');
}); // End of api Group
but when i send a post to /api/test it throws the crsf token mismatch. if i put the 'api/test' to the exception in the VerifyCsrftoken.php it works again. i cant figure out why the crsf token gets checked if not defined as a middelware for the route. Does anyone has an idea why?
CSRF is a "middleware" registered globally in App\Http\Kernel.php. Removing it will default to no CSRF protection (Laravel4 behavior).
To enable it in a route:
Create a short-hand key in your
app/Providers/RouteServiceProvider.php:
protected $middleware = [
// ....
'csrf' => 'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken',
];
You can now enable it to any Route:
$router->post('url', ['middleware' => 'csrf', function() {
...
}]);
Not really elegant but may be a spot on on your question, try it.

disable csrf in laravel for specific route

I've a payment system, where data is submitted to 3rd party site and than hauled back...
When data returns it hits specific url lets say /ok route. $_REQUEST['transaction'].
But because of laravel middleware I'm getting token mismatch. There is no way 3rd party payment API can generate token, so how I disable it? only for this route?
or is there a better option?
Route::get('/payment/ok', 'TransactionsController#Ok');
Route::get('/payment/fail', 'TransactionsController#Fail');
public function Ok( Request $request )
{
$transId = $request->get('trans_id');
if ( isset( $transId ) )
{
return $transId;
}
}
Since version 5.1 Laravel's VerifyCsrfToken middleware allows to specify routes, that are excluded from CSRF validation. In order to achieve that, you need to add the routes to $except array in your App\Http\Middleware\VerifyCsrfToken.php class:
<?php namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
protected $except = [
'payment/*',
];
}
See the docs for more information.
Since Laravel 7.7 you can use method withoutMiddleware eg:
Route::get('/payment/ok', 'TransactionsController#Ok')
->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);
Route::get('/payment/fail', 'TransactionsController#Fail')
->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);
The technique described by #jedrzej.kurylo works well for excluding one or two pages.
Here's a different technique if you need to exclude lots of pages from CSRF validation, with more future-proofing.
You can segment your routes, and apply different middleware to each. So you can put your payment routes into a separate route groups, and not apply VerifyCsrfToken to them. Here's how.
1. Create a routes file
You'll notice in your routes directory, you have the following tree:
routes/
routes/api.php
routes/web.php
Create a new file here, routes/payment.php, and add your routes above to it:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/payment/ok', 'TransactionsController#Ok');
Route::get('/payment/fail', 'TransactionsController#Fail');
2. Process the route with the RouteServiceProvider
In Laravel, Routes are processed by app\Providers\RouteServiceProvider.php. You'll notice these functions: map() and mapWebRoutes(). Add to this file accordingly (I've excluded the stock comments for brevity).
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
$this->mapPaymentRoutes(); // <---- add this line
}
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
protected function mapPaymentRoutes() // <--- Add this method
{
Route::middleware('payment') // <--- this line is important
->namespace($this->namespace)
->group(base_path('routes/payment.php'));
}
Notice we've added a new middleware layer. This is important for the next step.
3. Add a new middleware layer
Your middleware for your route groups are defined in App\Http\Kernel.php.
Update the $middlewareGroups property, and add a middle entry for 'payment'. It can be exactly the same as web, but without the VerifyCsrfToken line.
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\NoClickjack::class,
\App\Http\Middleware\SecureReferrerPolicy::class,
\App\Http\Middleware\NoXssScripting::class,
],
// ********** Add this *******************
'payment' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
// This is the line you want to comment-out / remove
// \App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\NoClickjack::class,
\App\Http\Middleware\SecureReferrerPolicy::class,
\App\Http\Middleware\NoXssScripting::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
🎉
Now whenever you add new routes that need to be excluded from the CSRF Token check, add them to the routes/payment.php file.

Categories