CakePHP 3.0使用单元格构建权限菜单

CakePHP 3.0使用单元格构建权限菜单,cakephp,menu,cakephp-3.0,Cakephp,Menu,Cakephp 3.0,我想在新的CakePHP3.0中创建一个菜单,我发现使用它可能是一个好方法。假设我创建了UserMenuCell 但我只想在当前用户被授权管理条形码时显示条形码项目。我怎么做?我甚至无法访问$this->Auth以获取当前用户 在我的手机模板中,一切正常。我只需要为菜单创建这个嵌套数组。如果传递会话变量 <?= $this->cell('userMenu', $this->Session->read('Auth')); ?> 我认为: 我可以使控制器具有静态方法

我想在新的CakePHP3.0中创建一个菜单,我发现使用它可能是一个好方法。假设我创建了UserMenuCell

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


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

如果传递会话变量

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

我认为:

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

然后我可以从任何地方调用,例如
PostsController::_isAuthorized($user,['action'=>'add'])
。我想这应该能解决所有的问题。 另一个好方法是将
$this->Auth->user()
传递到视图中,这样就可以在单元格中使用它(通过参数)

src/Controller/AppController.php

public function beforeFilter(Event $event) {
    $this -> set('user', $this -> Auth -> user());
}
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
    }
}
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
}
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);
}
src/View/Cell/MenuCell.php

public function beforeFilter(Event $event) {
    $this -> set('user', $this -> Auth -> user());
}
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
    }
}
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
}
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);
}
src/Template/Cell/Menu/display.ctp-仅演示如何渲染菜单

<ul>
    <?php foreach($menu as $item) {
        echo '<li>' . $this -> Html -> link ($item['title'], $item['url']);
    } ?>
</ul>
这是控制器的一个示例。您只能指定静态的
\u isAuthorized($user,$request)
方法,因为出于CakePHP默认行为的目的,它将从
AppController::isAuthorized
调用(请参见上面的代码)

src/Controller/PostController.php

public function beforeFilter(Event $event) {
    $this -> set('user', $this -> Auth -> user());
}
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
    }
}
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
}
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以接受数组Cake\Network\request对象。这是因为CakePHP使用Request对象调用它,但当我调用它时,我不需要创建这个对象,因为我的参数很简单(请参阅上面的代码MenuCell.php)

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

根据Cookbook,会话可以从单元格内进行

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

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

我不太喜欢此解决方案,因为您通过视图传递授权结构,这是一种不好的做法,请参阅以下讨论:。下面的建议似乎更好,因为您将Auth的知识保持在单元格的“控制器”级别,并且只向视图公开必要的数据。@RogerKaplan传递给视图的授权结构是什么?鉴于此,我只询问“用户是否有权查看某些内容”。我使用
PostsController::\u获得了授权
询问it控制器,但这不类似于Rails吗?他们有cancan gem,在视图中,您可以执行类似于
can?:显示,用户
。在您发布的链接中,您的确切代码是什么意思?在第一个代码段中,您通过视图变量$user将主Auth结构
$this->Auth->user()
传递到所有视图中。如果将机密传递给视图,只是为了让视图将它们传递回去,那么在控制器中保留go/no-go逻辑的事实是无关紧要的。从视图访问Auth的权限从cake3中被特别删除,我看到了一些与Mark Story的对话,为设计决策辩护(我忘了在哪里)。根据我对接受的答案的评论,我认为这是一种更干净的方法,因为它不需要通过视图传递Auth结构(它已经散列了pw…)。