Laravel 5.5 use of env string in route name screws Route::has()

时间:2018-02-03 10:18:17

标签: php laravel routes middleware

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'),

2 个答案:

答案 0 :(得分:1)

It's generally better to let the config files read the .env variables, and then load the settings from the config files where you actually need them. That way, they can be cached, and you virtually always know that they've already been read properly instead of having to wonder where they'll work and where they won't.

In your case, just something like this should be enough:

// in .env
APP_ADMIN_ROUTE=something

// in e.g. config/app.php
'admin-route' => env('APP_ADMIN_ROUTE');

// in the middleware
$adminRoute = config('app.admin-route');

I'm not 100 % sure this is actually your issue, but it's worth a shot - and even if it doesn't work, it's still a best practice. :)

答案 1 :(得分:0)

好的,第一个问题,第一个问题,看起来我没有探索所有可能性。

问题不是在路由URI定义中使用变量,而是使用Route::has()。这仅适用于路由名称,而不适用于路由URI。根据{{​​3}},检查路由是否存在的正确方法是使用Route::checkRoutes->match($testValue)$testValue成员的Illuminate \ Http \ Request。

Route::checkRoutes->match($testValue)将返回带有第一个匹配项的Illuminate \ Routing \ Route实例,如果没有匹配则返回空值。

在中间件句柄()上下文中,它可以表达如下:

$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
}

因此,正确的中间件完整代码是:

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('/');
}

这让我觉得这只是无用的代码块,因为中间件只会在现有的/ admin / something路由URI上触发,并且测试路由是否存在没有任何意义。

好吧,无论如何,感谢所有花时间阅读的人,看到你。