【问题标题】:Slim PHP Route in Middleware中间件中的 Slim PHP 路由
【发布时间】:2013-12-14 17:45:42
【问题描述】:

在 Slim 中是否可以在中间件中获取当前路由?

class Auth extends \Slim\Middleware{
  public function call(){ 
    $currentRoute = $this->app->getRoute(); // Something like this?
  }
}

我知道你可以在调用slim.before.dispatch 钩子之后调用$app->router()->getCurrentRoute(),但是当你从中间件调用它时它返回一个非对象。任何帮助将不胜感激。

【问题讨论】:

    标签: php middleware slim


    【解决方案1】:

    是和不是。如果你查看 Slim 的源代码,你会看到注册的中间件在调用 Slim::run 方法时以 LIFO 顺序被调用,然后 Slim 运行它自己的“调用”方法,开始处理请求。 Slim 正是在这种方法中解析和处理路由。在这种情况下,您无法在Middleware::call 方法中访问$app->router()->getCurrentRoute(),因为它还没有被解析和定义。

    做到这一点的唯一方法是在中间件内的slim.before.dispatch 上注册一个侦听器,并在该方法中实现您想要执行的任何操作。

    根据您的班级名称,我假设您正在尝试创建基本身份验证模块?我以前做过类似的事情,结果是这样的:

    class AuthMiddleware extends \Slim\Middleware
    {
        public function call()
        {
            $this->app->hook('slim.before.dispatch', array($this, 'onBeforeDispatch'));
    
            $this->next->call();
        }
    
        public function onBeforeDispatch()
        {
            $route = $this->app->router()->getCurrentRoute();
    
            //Here I check if the route is "protected" some how, and if it is, check the
            //user has permission, if not, throw either 404 or redirect.
    
            if (is_route_protected() && !user_has_permission())
            {
                $this->app->redirect('/login?return=' . urlencode(filter_input(INPUT_SERVER, 'REQUEST_URI')));
            }
        }
    }
    

    在本例中,onBeforeDispatch 方法将在调用路由处理程序之前运行。如果您查看源代码,您可以看到事件在 try/catch 块内触发,该块正在侦听 $app->redirect()$app->pass() 等引发的异常。这意味着我们可以在此处实现我们的检查/重定向逻辑就像这是一个路由处理函数一样。

    上面的is_route_protecteduser_has_permission 只是用来说明我的身份验证中间件如何工作的伪代码。我构建了这个类,以便您可以在中间件构造函数中为受保护的路由指定路由列表或正则表达式,以及传递实现用户权限检查的服务对象等。希望这会有所帮助。

    【讨论】:

    • 不错的一个。感谢您提供整洁的解决方案和详细的解释。在中间件的 call() 函数中注册钩子是一个好地方吗?看起来是这样,因为它保持整洁,只是想知道这是否会导致钩子被多次注册/调用?
    • 我认为可以安全地假设每个请求只会调用一次 call 方法。实际上,这取决于链中前一个中间件的实现,因为设计使用单链表,每个中间件调用下一个中间件。如果中间件在链调用方法中调用下一个中间件两次,尽管我建议它的 Doing It Wrong™,您可能应该停止使用它:)。
    【解决方案2】:

    有另一种方法可以做到这一点,因为我也遇到过同样的情况。我想避免的是通过路由匹配任何内容,而是想使用路由名称,因此您可以尝试以下操作:

    public function call() {
    
        $routeIWantToCheckAgainst = $this->slimApp->router()->urlFor('my.route.name');
        $requestRoute = $this->slimApp->request()->getPathInfo();
        if ($routeIWantToCheckAgainst !== $requestRoute) {
            // Do stuff you need to in here
        }
    
        $this->next->call();
    }
    

    您甚至可以拥有一个您不希望中间件在其上运行的路由数组,然后只需检查它是否是 in_array() 等,如果不是,请执行您需要的操作。

    【讨论】:

      【解决方案3】:

      你应该使用 app->request()->getPathInfo() 而不是 app->getRoute()。

      class Auth extends \Slim\Middleware{
          public function call(){ 
              $currentRoute = $this->app->request()->getPathInfo();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-04
        • 2014-03-19
        • 2015-02-14
        • 2017-10-03
        • 2015-03-17
        • 2018-09-11
        • 2016-06-01
        • 2016-04-01
        相关资源
        最近更新 更多