Slim 3 group routes name for middleware - php

According to the docs I can't set a name for group of routes in Slim 3.
In auth middleware I want to split routes for needed authentication and not. Like:
# These routes will return 302 redirect on auth false
$app->group('', function () use ($app) {
$app->get('/first', 'HomeCtrl:first')->setName('first');
$app->get('/second', 'HomeCtrl:second')->setName('second');
})->add(new \Lib\Middlewares\CheckSession());
# These routes will return 403 on auth false
$app->group('api/', function () use ($app) {
$app->get('users', 'UsersCtrl:getUsers')->setName('users');
$app->get('pages', 'PagesCtrl:getPages')->setName('pages');
})->add(new \Lib\Middlewares\CheckSession());
In the second group I want the auth middleware to return 403 for ajax calls instead of redirecting in the first.
I don't want to manage an array with names of all routes like suggested in this great answer. It should be a name of the group and based on it to decide what kind of response code to return.
I don't want to manage two middlewares either. I'm looking for an elegant solution for managing current routes group.

Slim 3 groups do not have names - they are essentially syntactic sugar that does two things:
Prepend an optional URL segment to a set of route definitions.
Apply middleware to a set of route definitions.
To do what you want to do, your CheckSession middleware needs to check the request's path to work out if it starts with api/ and do send a 403 in that case. Alternatively, CheckSession could look for the X-Requested-With header which is usually sent with ajax requests.

Related

Laravel Route Domain - skip some domain

Hi
My application has to work with several domains. But I need certain routers to be ignored by ONE specific domain (base.domain).
As a result, the routers must work with different domains than the base.domain
Help please, spent a lot of time and could not do it.
// this code doesn't need to work with "base.domain"
Route::group(['domain' => '{domain}.{ltd}'], function() {
//some routes
});
if the domain will be "base.domain" - these are the routers you should ignore and use the other ones.
I tried using middleware instead of the Route::domain, but it's fail :(
You can do this via middleware, create a subdomain middleware for route group and check for base domain in middleware and restrict to proceed further, something like below:
In your routes/web.php
Route::middleware(['subdomain'])->group(function(){
//some routes for subdomains only..
});
Create a new middleware in your app and define in $routeMiddleware under app/Http/Kernel.php
In app/Http/Middleware/Subdomain.php
public function handle($request, Closure $next){
if($_SERVER['HTTP_HOST'] == config('app.base_domain')){
// redirect to base domain
return redirect(config('app.base_domain'));
//Or your can abort the request 404
abort(404,'Not Found');
}
return $next($request);
}
Define base_domain variable in your config/app.php
That's it!

Slim Authentication middleware for all routes except someone

I would like to have a Slim middleware to check authentication on all requests but some specific ones (for example login page).
I prepared the first AuthenticationMiddleware middleware to check all pages:
$app->add(new \App\Middleware\AuthenticationMiddleware($container));
Then I create another one AnonymousMiddleware that it is supposed to add a variable to set the exception to authentication checks:
$app->group('',function() use ($app){
$app->get('/','LogicController:index');
})->add(new AnonymousMiddleware($container));
The problem is that routes middleware (AnonymousMiddleware) is applied AFTER the general middleware (AuthenticationMiddleware);
I tried to use determineRouteBeforeAppMiddleware but it doesn't change the result.
I know I would set a route middleware for all authenticated routes but sounds a bit dangerous if I forget it, so, I would prefer to set which router are not under authentication then keep the check all other routes.
you need to chose different approach
you need to wrap all routes which should be "protected via Auth middleware" and exclude = not wrap routes which should not be handled by this middleware
you can add a group where all your routes will live and only login (and logout) route will be outside of this group ;)
something like
$app->group("/api/v1", function() {
// all your protected routes definitions here
})
->add(AuthenticationMiddleware::class)); // wrap by middleware
$app->post('/login', function(){});
$app->add(new MiddlewareForAllRoutes()); // middlewares for all routes

Middleware 'auth' clarification

Im using Laravel 5.8 and I got the following situation:
I have a simple form with a button which sends a delete request to a route. The form works like this: When the button is pressed, the form's action redirects me to the URL localhost/delete/4 where 4 is the id of the entry in the database, and there the route kicks in and the controller deletes my entry.
However, unauthenticated users do not have access to the form's button, and the route is protected by the middleware 'auth'.
But, if I, as an unauthenticated user, type in the adress bar localhost/delete/4, I get a method unsupported error, which is expected because I send a get request to a delete type route.
But my question is why do I get this error at all? Since the route is protected by the middleware against unauthenticated users, why does the request reach the route since it should be blocked by the middleware?
Below you got the route:
Route::delete('/delete/{id}', ['uses' => 'LibraryController#getLibraryDelete', 'middleware' => 'auth']);
Oh, as a side note, if a change the route to receive get requests, and try again, the middleware works fine
The route is checked first before going to the middleware and controller...
So if the route was not found actually the script doesn't know which middleware or controller to go to...
--
Here is a good use case for example someone want to define the following routes
Route::get('/question/{id}', 'QuestionController#view');
GET /question/1 is public for all users and returns the question itself (read only)
but
Route::patch('/question/{id}', 'QuestionController#edit')->middleware('auth');
PATCH /question/1 is only authenticated user can edit question...
So it's acceptable that different methods can have different middlewares or no middlewares for the same route...
And that some methods are not defined/allowed
--
The method is unsupported because your defined route is for deletes only as in ::delete method you used
Delete request is either a HTTP POST request with a query called "_method" and value "delete" or in supported browser an HTTP DELETE request
When the user type the url manually in their address bar it's a GET request which can be handled by this route method ::get
Available routing methods from latest documentation: (https://laravel.com/docs/5.8/routing)
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
Plus special route ::any which accepts any method
In laravel if the user reach a url that is defined but with a Method that's not defined in routes you get this "Method unsupported"
The method unsupported error is irrelevant to auth middleware in this case ... it's just about routing

Laravel Forwarding Route To Another Route File

I'm building enterprise modular Laravel web application but I'm having a small problem.
I would like to have it so that if someone goes to the /api/*/ route (/api/ is a route group) that it will go to an InputController. the first variable next to /api/ will be the module name that the api is requesting info from. So lets say for example: /api/phonefinder/find
In this case, when someone hit's this route, it will go to InputController, verifiy if the module 'phonefinder' exists, then sends anything after the /api/phonefinder to the correct routes file in that module's folder (In this case the '/find' Route..)
So:
/api/phonefinder/find - Go to input controller and verify if phonefinder module exists (Always go to InputController even if its another module instead of phonefinder)
/find - Then call the /find route inside folder Modules/phonefinder/routes.php
Any idea's on how to achieve this?
Middlewares are designed for this purpose. You can create a middleware by typing
php artisan make:middleware MiddlewareName
It will create a middleware named 'MiddlewareName' under namespace App\Http\Middleware; path.
In this middleware, write your controls in the handle function. It should return $next($request); Dont change this part.
In your Http\Kernel.php file, go to $routeMiddleware variable and add this line:
'middleware_name' => \App\Http\Middleware\MiddlewareName::class,
And finally, go to your web.php file and set the middleware. An example can be given as:
Route::middleware(['middleware_name'])->group(function () {
Route::prefix('api')->group(function () {
Route::get('/phonefinder', 'SomeController#someMethod');
});
});
Whenever you call api/phonefinder endpoint, it will go to the Middleware first.
What you are looking for is HMVC, where you can send internal route requests, but Laravel doesn't support it.
If you want to have one access point for your modular application then you should declare it like this (for example):
Route::any('api/{module}/{action}', 'InputController#moduleAction');
Then in your moduleAction($module, $action) you can process it accordingly, initialize needed module and call it's action with all attached data. Implement your own Module class the way you need and work from there.
Laravel doesn't support HMVC, you can't have one general route using other internal routes. And if those routes (/find in your case) are not internal and can be publicly accessed then also having one general route makes no sense.

Laravel 4 routing - the ability to skip a route if conditions are not met

So we have a load of content within the database, let's call these Articles. The paths for the Articles start from the application root and can contain slashes. So we want to search the DB to see if we match an Article, and if not skip the route and give other routes the opportunity to respond.
In Sinatra (which I believe has inspired the routing within Laravel) you have the option to pass to the next route. It might be this that's leading me astray.
Route::get( '{uri}', function( URI $uri ) {
// check database, if we find a record we'll need to pass it to the appropriate controller
// we'll have a class that handles this responsiblity
// pass if we don't find anything
} )->where('uri', '.*');
Route::get( 'other/page', 'OtherController#sayHello' );
The issue Allow skip the route based on conditions #1899 talks about this, although I can't see how filters cater for this, they will simply intercept and give you an opportunity to stop route execution (throw exception, redirect to route specifically etc.), you can't return FALSE; without error. There is an example chaining a condition method to a route, although this method doesn't seem to exist (in 4.2).
Any ideas?
In addition to this, we're also are thinking about containing this logic within a package so it can be shared across applications, and wonder if you can influence the order of execution of routes provided by package?
You can have a group of routes, which you contain within all the routes that match it. If it fails that group then it skips to the next section.
Route::group(array('before' => 'auth'), function()
{
Route::get('/', function()
{
// Has Auth Filter
});
Route::get('user/profile', function()
{
// Has Auth Filter
});
});
http://laravel.com/docs/4.2/routing

Categories