【问题标题】:How to use hook_menu_alter() to manipulate path access control如何使用 hook_menu_alter() 来操作路径访问控制
【发布时间】:2011-02-26 02:00:12
【问题描述】:
/**
 * Implementation of hook_menu_alter().
 */
function joke_menu_alter(&$callbacks) {
  // If the user does not have 'administer nodes' permission,
  // disable the joke menu item by setting its access callback to FALSE.
  if (!user_access('administer nodes')) {
    $callbacks['node/add/joke']['access callback'] = FALSE;
    // Must unset access arguments or Drupal will use user_access()
    // as a default access callback.
    unset($callbacks['node/add/joke']['access arguments']);
  }
}

以上功能来自pro development drupal。我不能很好地理解它。为什么我必须取消设置访问参数(unset($callbacks['node/add/joke']['access arguments']);)

谢谢。

【问题讨论】:

    标签: drupal drupal-6 drupal-modules


    【解决方案1】:

    整个例子看起来很糟糕而且很糟糕。简而言之,一个笑话。首先,让我回答你的问题,然后我会继续解释为什么你不应该在实践中遵循这个例子。

    来自includes/menu.inc

    if (!isset($item['access callback']) && isset($item['access arguments'])) {
      // Default callback.
      $item['access callback'] = 'user_access';
    }
    

    当您不再需要访问回调时取消设置访问回调(毕竟现在依赖于布尔值)可以防止 Drupal 路由系统中过于聪明的逻辑在 user_access() 中被拍打,所以它有事可做。

    现在,谈谈为什么这是糟糕的代码。

    hook_menu()hook_menu_alter() 都在缓存清除时运行(更具体地说,在重建菜单路由系统时)。这意味着无论哪个用户访问该站点以重建菜单的权限都将被硬编码到菜单路由行为中。这是一个非常糟糕和不一致的安排。

    如果您想根据权限阻止对路径的访问,您需要将回调更改为可以测试该权限的内容。然后当菜单重建时,它会检查每次页面加载的新回调函数,看看当前用户是否应该被授予权限。

    一个简单的例子可能如下所示:

    /**
     * Implementation of hook_menu_alter().
     */
    function joke_menu_alter(&$items) {
      $items['node/add/joke']['access callback'] = 'user_access';
      $items['node/add/joke']['access arguments'] = array('administer nodes');
    }
    

    现在我们有一个函数,它采用节点/添加/笑话路径并声明唯一重要的是用户是否具有administer nodes 权限。当然,这比示例的明显意图更受限制,即保留现有的访问控制,但还要求用户拥有administer nodes 权限。

    这也是可以修复的,但更复杂。借用Spaces项目的一些概念:

    /**
     * Implementation of hook_menu_alter().
     */
    function joke_menu_alter(&$items) {
      $path = 'node/add/joke';
      $items[$path]['access arguments'][] = $items[$path]['access callback'];
      $items[$path]['access callback'] = 'joke_menu_access';
    }
    
    function joke_menu_access() {
      $args = func_get_args();
      $access_callback = array_pop($args);
      $original_access = call_user_func_array($access_callback, $args);
      return $original_access && user_access('administer nodes');
    }
    

    我们已经成功地将原始访问回调封装在一个新的访问回调中,我们可以在其中添加任何我们需要的额外逻辑。

    请注意,在最后两个函数示例中,我使用了$path 变量来保持代码简单。我还将$original_access 分隔到它自己的行中并首先对其进行检查,实际上我会先检查user_access(),因为它几乎肯定会比原始访问回调中发生的任何事情都具有更高的性能。

    【讨论】:

    • 我只是想感谢您,即使在投票后,您不仅告诉 OP 如何,而且 为什么!哦,我希望当答案如此深入时能加 10。
    【解决方案2】:

    该行正上方的注释说明了这一点?

    访问回调是被调用的函数(或 TRUE/FALSE),参数是传递给该函数的内容。您将回调设置为 false,因此始终拒绝访问该路由器项。

    现在,正如评论所说,您还需要取消设置参数,否则 Drupal 仍将使用 user_access() (默认访问回调)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-11
      • 2013-06-25
      • 1970-01-01
      • 1970-01-01
      • 2017-10-24
      • 2015-06-13
      • 2023-03-14
      相关资源
      最近更新 更多