如何使用hook_menu_alter()来操作路径访问控制

时间:2011-02-26 02:00:12

标签: drupal drupal-6 drupal-modules

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

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

谢谢。

2 个答案:

答案 0 :(得分:19)

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

来自 includes / menu.inc

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

当你不再需要它们时取消设置访问回调(毕竟现在依赖于布尔值)可以防止Drupal路由系统中的过度聪明逻辑在user_access()中打包,只是为了让它有事可做。 / p>

现在,为什么这是错误的代码。

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

现在我们有一个函数接受node / add / joke路径并声明 only 重要的事情是用户是否具有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(),因为它几乎肯定会比原始访问回调中的任何内容更高效。

答案 1 :(得分:2)

该行正上方的评论解释了它?

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

现在,正如评论所说,你还需要取消设置参数,或者Drupal仍然会使用user_access()(默认访问回调)。