任何一个开放系统(Open System), 只要它与外界有接口, 就存在安全问题, 越是商业级应用越注重安全. 安全管理涉及很广, 大到整个网络安全的设定,小到具体按钮的访问, 如果你的系统哪天出现安全问题, 没准追根溯源能找到机房看门老头, 呵呵, 玩笑话略过, 今天我们主要看看Drupal的用户权限管理, 也就是访问控制系统.
权限管理的要素
我认为, 一个权限管理系统主要由以下四要素组成: 访问者, 管理对象, 操作和规则.
- 访问者: 谁干? who. 一般来说是人, 严格来说应该叫主动体, 这要看你的系统面向哪些用户, 一般系统人机接口,机机接口都是存在的. 反正就是那些通过你系统开发的接口与你交互的东东.
- 管理对象: 干谁? which. 就是被管理的东西, 比如仓库里的粮食, 博客系统的文章, 总之, 任何有管理要求的东西. 千万要记住的一点是: 就算垃圾也是有管理要求的.
- 操作: 干什么? what. 对应具体操作, 比如写文章, 运粮食, 倒垃圾...
- 规则: 怎么干? how, when, where, 定义操作实施的附加条件, 比如登陆时间等.
权限管理的系统功能
可以说, 自从有了安全问题, 大家就在围绕这几个要素伤脑筋, 针对各种不同的管理需求, 也出现了各种不同的权限管理的方案, 如何在安全性, 操控性, 性能以及开发复杂性间取得平衡是恒古不变的主题. 为了聚焦今天的话题, 我们主要从系统功能角度来窥视一下, 看看一个权限系统到底是如何工作的.
- 首先当然权限的定义, 即识别出系统中需要进行访问控制的要素(管理对象, 操作, 规则), 并定义成相应的权限, 这是整个权限系统的核心, 针对不同的管理粒度和管理要求, 会出现截然不同的实现方式.
- 授权, 即把权限与用户关联, 最直接的方法是给用户直接关联, 而最常见最有效的方式是使用角色(也有叫组的)
- 鉴权, 根据规则执行权限的检查, 以实施访问控制, 看你的检查点实现在哪呢, 同样也是不同的要求有不同的实现
- 最后, 应该要能监控, 一般记日志
是不是比较清楚, 把这几个系统功能考虑完全, 并实现好, 你的系统就安全了一半; 另一半是什么, 是你的安全意识, 天干物燥, 防火防盗, 只有真正树立安全意识, 才能有效地去应用各种安全措施, 防范危险. 不幸的是, 我们大多数人都疏予管理, 闲置, 不管不顾.
Drupal的权限管理框架
首先我们来识别系统中具备哪些要素: Drupal是一个基于web的CMS系统, 所以访问者主要局限在管理员和普通web访问用户(User); 而管理对象则是CMS中的核心--内容, 在drupal中它被抽象为节点(Node). (应该还会有些其他的管理对象). 操作呢? 菜单, 按钮, 在web系统里是不是都对应到页面, 也就是内部路径(例如: "node/1/view"), 规则没什么特殊的: 操作时出现禁止页面, 列表中不出现无权限内容等.
Drupa采用角色来关联用户和操作, 每个角色是从方便系统管理角度出发来定义的一类具备相同操作界面或行为的访问者, 但它不是简单的用户或操作的分组, 而是他们的有机结合, 形象的说就是一组权力的代名词或者叫Permission Scheme. Drupall针对操作是否涉及到管理对象, 设计了两个不同的鉴权流程, 以满足不同的权限管理要求.
(1)与内容无关的操作权限
权限定义
钩子hook_perm, 定义了每个模块的操作权限, 用操作名描述.
<?php
/**
* Implementation of hook_perm().
*/
function book_perm() {
return array(‘add content to books‘, ‘administer book outlines‘, ‘create new books‘, ‘access printer-friendly version‘);
}
?>
授权
按角色授权, 权限被分配后, 存储在数据库表{permission}中.
鉴权
由函数user_access进行实际的鉴权工作, 它的参数是账号信息与操作权限名, 返回ture或false. 你可以在任何需要的地方调用该函数进行鉴权, 但系统提供了一套默认的回调机制, 使得鉴权点实现简单一致. 这就是菜单路由注册函数中的access_callback参数, 该参数标明了此菜单路由需要进行访问控制, 只有访问回调函数验证通过, 才会被正确路由到对应页面.
<?php
function forum_menu() {
$items[‘forum‘] = array(
‘title‘ => ‘Forums‘,
‘page callback‘ => ‘forum_page‘,
‘access callback‘ => ‘_example_test_access‘, //这里指定访问验证回调函数, 默认为hook_access()钩子,
‘access arguments‘ => array(‘access content‘),
‘type‘ => MENU_SUGGESTED_ITEM,
‘file‘ => ‘forum.pages.inc‘,
);
?>
鉴权钩子, 模块可以处理一些特殊的规则
<?php
/**
* Implementation of hook_access().
*/
function forum_access($op, $node, $account) {
switch ($op) {
case ‘create‘:
return user_access(‘create forum topics‘, $account);
case ‘update‘:
return user_access(‘edit any forum topic‘, $account) || (user_access(‘edit own forum topics‘, $account) && ($account->uid == $node->uid));
case ‘delete‘:
return user_access(‘delete any forum topic‘, $account) || (user_access(‘delete own forum topics‘, $account) && ($account->uid == $node->uid));
}
}
?>
(2)节点访问机制(Node Access System)
drupal还提供对管理对象的访问控制-- 节点访问机制(Node Access System), 这是一套复杂的机制, 我还没完全摸清. 它主要是在权限定义方面进行了增强, 它通过定义用户, 操作与节点的绑定, 来建立一个节点访问表, 这样当需要进行管理对象关联鉴权时, 系统会执行node_access函数, 该函数会恰当地查询节点访问表获得用户的权限, 以完成鉴权.
我们再来看看这张节点访问表, 用户信息, 操作信息, 节点信息, OMG! m*n*P=? 如果还是按以前方式来定义, 那性能的低下可想而知, 所以综合一般的权限控制需求, Drupal仅定义了三种的原始操作: view, update, delete, 而对于用户则仅定义了一个抽象的二元组(realm, grant), 它与实际用户间的映射由你自定义的节点访问控制模块行来决定, 这样达到对用户归纳的效果, 减小节点访问表纪录的数量级.
这套机制主要通过节点模块(Node Module)提供的一系列api和 hook_node_grants钩子和hook_node_access_records钩子来实现. 我们这次知道有这套东西即可, 不铺开叙述.
Drupal的权限管理方法
1, 基本权限管理
尽管Drupal的权限管理机制是强大复杂的, 但其默认的基本权限管理却非常简单, 基于角色(role)和操作权限, 把操作赋予角色, 而把角色赋予用户, 这样用户就能使用相应的权限. 基本权限管理粒度较粗, 只能满足一般的安全需求.
2, 按内容类型鉴权
如果我们对管理对象有更精细的管理要求, 比如我想让A角色能访问page, B角色只能访问story, 咋办? 基本权限管理做不到了, 那我们就扩展模块. 内容访问模块(Content Access )允许你对内容类型按角色设置权限(查看, 编辑, 删除). 其实Drupal6.2基本权限管理里也能设置按内容类型进行鉴权, 因为drupal把所有节点类型的几个基本操作都注册了, 看下面这个丑陋的循环, 呵呵, 这几个也是汉化不到位的地方.
<?php
function node_perm() {
$perms = array(‘administer content types‘, ‘administer nodes‘, ‘access content‘, ‘view revisions‘, ‘revert revisions‘, ‘delete revisions‘);
foreach (node_get_types() as $type) {
if ($type->module == ‘node‘) {
$name = check_plain($type->type);
$perms[] = ‘create ‘. $name .‘ content‘;
$perms[] = ‘delete own ‘. $name .‘ content‘;
$perms[] = ‘delete any ‘. $name .‘ content‘;
$perms[] = ‘edit own ‘. $name .‘ content‘;
$perms[] = ‘edit any ‘. $name .‘ content‘;
}
}
return $perms;
}
?>
3, 按组鉴权
如果是个大公司, 有很多部门, 相互间都有安全需求, 比如:
1. 能按不同的部门创建不同的组, 它们都能管理其私有内容
2. 组成员拥有组内的权限
3. 跨组间允许指定某些特定的权限共享
4. 匿名用户只能访问标识为"public"的内容, 注册用户能访问public和Restricted, 仅组成员能访问private等
看到这么多需求, 则我们需要一个更复杂的权限管理, drupal目前有两个扩展模块都能提供类似的功能:
(a) taxonomy_access modules
使用drupal的分类模块的基本功能, 完成以上的权限控制, 这里有英文的教程, 步骤描述较清楚.
i, 定义一个词汇表(Groups), 用来定义组(即公司部门); 把它应用到所有内容类型, 再添加2个条目(比如财务, 研发)
ii, 再定义一个词汇表(Access), 用来定义访问级别; 同样应用到所有内容类型, 同时还要设置"必须"的选项, 这样保证创建内容时必须选一个该
词汇表中的条目. 加三个条目(public, Restricted, Private)
iii, 按基本权限管理的方法创建2个角色(财务人员, 开发人员), 再创建几个用户, 并分辨赋予对应角色(张三->财务, 李四->开发)
iv, 前面都是基本管理,没涉及到扩展模块, 现在打开"administer > user management > taxonomy access: permissions", 按照步骤开始设吧, 一个组鉴权系统完成, 祝你好运.
(b) 著名的OG
Organic Groups功能太强了, 上面的需求全部能满足, 组或圈的概念是大型社区不可缺少的, 别犹豫了, 能用就用吧.
总之, drupal的权限管理机制非常灵活, 可简可繁, 每个系统都安全的需求都是不一样的, 你们的权限管理有哪些特殊的好实现, 拿出来show绣把.