【问题标题】:CakePHP 3.0 build a permission menu using CellsCakePHP 3.0 使用 Cells 构建权限菜单
【发布时间】:2014-08-23 14:37:33
【问题描述】:

我想在新的 CakePHP 3.0 中创建一个菜单,我发现使用 cells 可能是一个好方法。所以假设我创建了 UserMenuCell

class UserMenuCell extends Cell {
    protected $_validCellOptions = [];

    public function display() {
        $menu = [];

        $menu[] = $this ->menu( __('Dashboard'), array( 'controller' => 'Users', 'action' => 'dashboard' ), 'fa-dashboard', [] );

        if( $this -> Auth -> isAuthorized(null, ??? ))
            $menu[] = $this ->menu( __('Barcodes'), array( 'controller' => 'Barcodes', 'action' => 'index' ), 'fa-table', [] );

        $this -> set ( 'menu',  $menu );
    }

    private function menu( $title, $url = [], $icon, $submenu = [] ) {
        return ['title' => $title, 'url' => $url, 'icon' => $icon, 'submenu' => $submenu]; }
}

但我只想在当前用户被授权管理条形码时才显示 Barcodes 项。我该怎么做?我甚至无法访问 $this -> Auth 来获取当前用户。

在我的单元格模板中一切正常。我只需要为菜单创建这个嵌套数组。

【问题讨论】:

    标签: cakephp menu cakephp-3.0


    【解决方案1】:

    根据 Cookbook,该会话可在 Cells 中使用。

    class UsermenuCell extends Cell
    {
        public function display()
        {
            var_dump($this->request->session()->read('Auth'));
        }
    }
    

    这样您就可以在单元格显示功能中读取所需的信息。

    【讨论】:

    • 根据我对已接受答案的评论,我认为这是一种更简洁的方法,因为它不需要通过视图传递 Auth 结构(已散列 pw ...)。
    【解决方案2】:

    如果你传递会话变量?

    <?= $this->cell('userMenu', $this->Session->read('Auth')); ?>
    

    【讨论】:

      【解决方案3】:

      我认为problem is solved

      我可以使控制器具有静态方法,例如静态公共函数_isAuthorized($user, $request),它将处理授权逻辑(因此每个控制器只控制自己的权限)。

      然后我可以从任何地方拨打电话,例如PostsController::_isAuthorized($user, ['action' =&gt; 'add'])。这应该可以解决我猜的所有问题。 另一个好处是将$this -&gt; Auth -&gt; user() 传递到视图中,这样它就可以在Cells中使用(通过参数)。

      src/Controller/AppController.php

      public function beforeFilter(Event $event) {
          $this -> set('user', $this -> Auth -> user());
      }
      

      src/View/Cell/MenuCell.php

      use App\Controller\PostsController; // Don't forget to use namespace of your Controller
      
      class MenuCell extends Cell {
          public function display($user) {
              $menu = [];
              if (PostsController::_isAuthorized($user, ['action' => 'add'])) // In that method you must handle authorization
                  $menu[] = ['title' => 'Add post', 'url' => array('controller' => 'Posts', 'action' => 'add')];
             $this -> set ('menu', $menu); // Handle this in Template/Cell/Menu/display.ctp
          }
      }
      

      src/Template/Cell/Menu/display.ctp - 只是为了展示如何渲染菜单

      <ul>
          <?php foreach($menu as $item) {
              echo '<li>' . $this -> Html -> link ($item['title'], $item['url']);
          } ?>
      </ul>
      

      src/Template/Layout/default.ctp - 在主布局中渲染菜单

      <?= $this -> cell('Menu', array($user)) /* This is the user passed from beforeFilter */ ?>
      

      然后您可以使用isAuthorized 方法。例如,您可以编辑您的AppController。当CakePHP 调用isAuthorized 函数时,它总是会被重定向到YourNameController::_isAuthorized() 静态方法(如果存在)。

      src/Controller/AppController.php

      public function isAuthorized( $user ) {
          $childClass = get_called_class();
      
          if(method_exists($childClass, '_isAuthorized'))
              return $childClass::_isAuthorized($user, $this -> request);
      
          return static::_isAuthorized($user, $request);
      }
      
      static public function _isAuthorized($user, $request)
      {
          if ($user['role'] == 'admin')
              return true;
      
          return false; // By default deny any unwanted access
      }
      

      这是您的控制器的示例。您只能指定静态_isAuthorized($user, $request) 方法,因为出于CakePHP 默认行为的目的,它将从AppController::isAuthorized 调用(参见上面的代码)。

      src/Controller/PostController.php

      static public function _isAuthorized($user, $request)
      {
          $action = ($request instanceof Cake\Network\Request) ? $request -> action : $request['action'];
      
          if($action == 'add' && $user['role'] == 'CanAddPosts')
              return true;
      
          return parent::_isAuthorized($user, $request);
      }
      

      如您所见,我让 $request 接受 arrayCake\Network\Request 对象。那是因为 CakePHPRequest 对象调用它,但是当我调用它时,我不需要创建这个对象,因为我的参数很简单(参见上面的代码 MenuCell .php)。

      当然你现在可以做更复杂的逻辑,比如用户可以有更多的角色,用逗号分隔,你可以explode这个并检查用户是否有in_array的权限。 现在,您的权限背后的逻辑是什么,这完全取决于您。每个控制器都可以处理自己的权限管理,而您始终可以通过每个用户和每个页面请求访问这些权限。

      【讨论】:

      • 我不太喜欢这种解决方案,因为您通过视图传递授权结构,这是一种不好的做法,请参阅此讨论:link。下面的建议似乎更好,因为您将 Auth 的知识保持在单元的“控制器”级别,并且只向视图公开必要的数据。
      • @RogerKaplan 传递什么授权结构来查看?在视图中,我只询问“用户是否有权查看某些内容”。我问它使用PostsController::_isAuthorized 的控制器,但这不是类似于Rails 吗?他们有康康宝石,您可以在视图中执行can? :show, User 之类的操作。从您发布的链接中,您的确切代码是什么意思?
      • 在第一个代码段中,您通过视图变量 $user 将 $this-&gt;Auth-&gt;user() 这是主要的身份验证结构传递到所有视图中。如果您将秘密传递给视图,只是让视图将它们传回,那么您将 go/no go 逻辑保留在控制器中的事实是无关紧要的。从 cake3 中特别删除了从视图中访问 Auth,我看到了一些与 Mark Story 为该设计决策辩护的对话(我忘记了在哪里)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 2016-04-09
      • 1970-01-01
      • 2011-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多