For absolute testing purpose (it's probably not a consistent behaviour I'll keep on my code) I try to use a custom admin pannel route set with the .env file (As it seemed relevant in securing the whole thing, but not so sure anymore).
As I want that people visiting the site can see that admin pannel in guest mode, I thought it would be cool to set a rerouting middleware that simply put a guest after that .env set admin route. Guests who try to get to /admin/jobs would end on /admin/guest/jobs with lowered permission controller.
The code below works fine without the .env thingy.
It's set like this in \Route\web.php
Route::namespace('Admin')->middleware('auth')->group(function () {
$adminRoute = config('app.admin-route');
$adminRoute = (preg_match('/[\/].*/', $adminRoute)) ? $adminRoute : '/' . $adminRoute;
Route::middleware('isadmin')->group(function () use ($adminRoute) {
Route::get($adminRoute, 'AdminController@index')->name('adminPanel');
Route::get($adminRoute . '/test', function () {
echo 'test';
});
});
Route::get($adminRoute . '/guest/{where?}', 'AdminController@guest')->where('where', '.*')->name('adminAsGuest');
});
And the corresponding isAdmin middleware:
public function handle($request, Closure $next)
{
$adminRoute = config('app.admin-route');
$adminRoute = (preg_match('/\/.*/', $adminRoute)) ? $adminRoute : '/' . $adminRoute;
// check if authentified
if (Auth::check())
{
// check if admin
if (Auth::user()->role == 1) {
return $next($request);
}
else
{
$route = "/".$request->route()->uri;
// check if route exists
if (Route::has($route)) {
// trim the route after admin and puts a guest inside
$redirect = preg_replace("/\\".$adminRoute."/", "", $route);
return redirect($adminRoute . '\/guest/' . $redirect);
}
else {
// if it doesn't, let it go to the laravel error
return $next($request);
}
}
}
// if auth middleware was used on same route, won't go there anyways
// if not, redirect to root route
return redirect('/');
}
I'm on a struggle there as Route::has($route)
doesn't trigger correctly as long as I use env("APP_ADMIN_ROUTE") as the root of the admin routes.
Here's my debugging outputs just before if (Route::has($route))
Auth::check()
true
Auth::user()->role
0
$route
"/admin/test"
Route::has($route);
false
vagrant@ubuntu-xenial:/var/www/html$ wphp artisan route:list
+--------+----------+------------------------+------------------+------------------------------------------------------------------------+------------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+------------------------+------------------+------------------------------------------------------------------------+------------------+
| | GET|HEAD | / | | App\Http\Controllers\WelcomeController@index | web |
| | GET|HEAD | admin | adminPanel | App\Http\Controllers\Admin\AdminController@index | web,auth,isadmin |
| | GET|HEAD | admin/guest/{where?} | adminAsGuest | App\Http\Controllers\Admin\AdminController@guest | web,auth |
| | GET|HEAD | admin/test | | Closure | web,auth,isadmin |
I know it would certainly be more consistent to go for admin controllers in which I constantly track the role of the user connected, and give there or not the right to modify things. But I'm really curious to know if there's any possible way to work it like I tried here.
I've seen Zizaco/entrust and it would certainly work great on a simplier approach, and it's my next step if there's no positive answer to my current issue :)
Here's my first question on StackOverflow. I used great search for that precise thing without success. I apologize if I missed an obvious answer somewhere.
Edit: Updated the code after Joel Hinz's comment.
// \Config\app.php
'admin-route' => env('APP_ADMIN_ROUTE', 'admin'),
Okay, first question, first anwer, looks like I didn't explore all possibilities.
The issue wasn't using variables in route URI definition, but an improper use of Route::has()
. This works only with route names, and not route URI. Proper way to check if a route exists, according to https://laracasts.com/discuss/channels/general-discussion/check-if-route-exists is to use a Route::checkRoutes->match($testValue)
with a $testValue
member of Illuminate\Http\Request.
Route::checkRoutes->match($testValue)
will return a Illuminate\Routing\Route instance with the first match, and an empty value if there's no match.
In a middleware handle() context it can articulates like this:
$route = "/" . $request->route()->uri;
// Shape your test route URI in a request
$testValue = $request->create($route);
// check if route exists
if (Route::getRoutes()->match($testValue)) {
// statements here
}
So, the correct middleware complete code is:
public function handle($request, Closure $next)
{
$adminRoute = config('app.admin-route');
$adminRoute = (preg_match('/\/.*/', $adminRoute)) ? $adminRoute : '/' . $adminRoute;
// check if authentified
if (Auth::check())
{
// check if admin
if (Auth::user()->role == 1) {
return $next($request);
}
else
{
$route = "/" . $request->route()->uri;
$nreq = $request->create($route);
// check if route exists
if (Route::getRoutes()->match($nreq)) {
// trim the route after admin and puts a guest inside
$redirect = preg_replace("/\\".$adminRoute."/", "", $route);
return redirect($adminRoute.'/guest' . $redirect);
}
else {
// if it doesn't, let it go to the laravel error
return $next($request);
}
}
}
// if auth middleware was used on same route, won't go there anyways
// if not, redirect to root route
return redirect('/');
}
What leads me in the way of thinking this is only useless code block as the middleware will only trigger on an existing /admin/something route URI, and testing if route exists there makes no point.
Well, anyways, thanks to everyone who took time to read that, see you around.