Moodle API文档 —— Access API

Moodle中的Access API通过capabilities的方式向我们提供了判断当前用户权限的一些函数。它同样允许一些继承于moodle的模块来自定义新的capabilities.

概述

moodle使用基于角色的访问控制模型。大多数的moodle实体(系统(system)、用户(users)、课程类别(course categories)、课程(courses)、课程模块(modules)、块(blocks))都有一个上下文(context),它们被组织在一个叫做上下文树(context tree)的树形结构中。角色是一个权限(capability)的集合,每一个capability通常代表一个用户能做什么事的能力。角色定义在大多数系统的上下文层级。角色定义可以被重写。用户访问控制则是通过查询用户所属的角色的定义来判断用户是否有相应的权限。

所有未登录的用户自动获取定义在$CFG->notloggedinroleid中的默认角色,该角色不能被其他的任何角色引用。在自动以访客身份登录的模式(guest autologin)启用时,未登录的用户使用的默认角色则是定义在$CFG->guestroleid中的访客角色。当然,你也不能让其他角色引用访客角色。所有其他的经过身份验证的用户则自动获取定义在$CFG->defaultuserroleid中的默认角色。他们在打开首页时使用的默认角色则被定义在$CFG->defaultfrontpageroleid中。

如何在插件中定义新的权限

权限被定义在文件db/access.php中,是一个名为$capabilities的数组。它的命名规则为”插件类型/插件名:权限名”。

举个栗子:

1
2
3
4
5
6
7
8
9
10
$capabilities = array(
'mod/folder:managefiles' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW
)
),
);

其中的关键字的含义如下:

  • riskbitmask:该项权限相应的风险。关于risk在之后的文档中会有介绍。
  • captype:权限类型(读/写)。出于安全的考虑,系统会对访客和未登录用户规避写权限。
  • contextlevel:定义上下文的层级。即这项权限在被应用时所属的典型层次。当这项权限在多个层级被使用时,则定义为最低的一个层级。这保证了它可以被高级层级的权限重写。
  • archetypes:指定角色的默认值默认值和标准原型。这被用于插件的安装、更新、和重置角色的时候。archetypes定义在mdl_role表中。关于角色原型也会在之后的文档中介绍。
  • clonepermissionsfrom:当你想添加一个新的权限时,你可以让moodle复制在其中定义的所有角色的当前权限的集合。在定义一些较为庞大的权限时(例如管理员权限),这可能比使用archetypes要更方便。他的语法形如:'clonepermissionsfrom' => 'moodle/quiz:attempt'

如果你对db/assess.php进行了任何形式的修改,那么你应该同时提高当前插件的版本号,从而使升级脚本可以对数据库进行相应的修改。如果你需要运行升级脚本,只需要以管理员账户登录moodle系统并根据提示进行操作即可。

权限的名称被定义在插件的语言包中,其命名规则为”插件名:权限名”。例如:

1
$string['folder:managefiles'] = 'Manage files in folder module';

一些可能用到的函数和类

上下文的获取

在插件中,上下文的实体往往是唯一的。因为他们会被系统自动实例化和删除。

通过对象id获取:

1
2
3
4
5
$systemcontext = context_system::instance();
$usercontext = context_user::instance($user->id);
$categorycontext = context_coursecat::instance($category->id);
$coursecontext = context_course::instance($course->id);
$contextmodule = context_module::instance($cm->id);

通过上下文id获取:

1
$context = context::instance_by_id($contextid);

注意:

  • 如果上下文不能正常创建会抛出异常
  • 被删除的用户不会再有上下文

判断某个用户是否具有指定的权限

在实现访问控制时,我们会通过询问“用户有能力做某事吗?”来实现,而不是“用户有某个角色吗?”

has_capability()

has_capability()是访问控制中最重要的一个函数

1
function has_capability($capability, context $context, $user = null, $doanything = true)

在检查某个用户是否具有指定的权限时,我们会这样使用它:

1
2
$context = context_module::instance($cm->id);
has_capability('mod/folder:managefiles', $context)

默认情况下上述代码是在检查当前用户的权限,当然你也可以传入用户id用以检查指定用户的权限。

一般来说,在检查管理员的所有权限时,都应该返回true,在写代码时应注意这一点。

require_capability()

require_capability()函数也是很常见的,它会在用户没有该项权限时抛出访问控制异常(access control exception)。

1
function require_capability($capability, context $context, $userid = null, $doanything = true, $errormessage = 'nopermissions', $stringfile = '')

和选课相关函数

会在之后的文档中介绍

其他相关的函数

1
2
3
4
5
6
7
8
9
function require_login($courseorid = NULL, $autologinguest = true, $cm = NULL, $setwantsurltome = true, $preventredirect = false)
function require_course_login($courseorid, $autologinguest = true, $cm = NULL, $setwantsurltome = true, $preventredirect = false)
function get_users_by_capability(context $context, $capability, $fields = '', $sort = '', $limitfrom = '', $limitnum = '',
$groups = '', $exceptions = '', $doanything_ignored = null, $view_ignored = null, $useviewallgroups = false)
function isguestuser($user = null)
function isloggedin()
function is_siteadmin($user_or_id = null)
function is_guest(context $context, $user = null)
function is_viewing(context $context, $user = null, $withcapability = '')

require_login()

每个插件脚本在设置了$PAGE->url之后,都应该执行require_loginrequire_course_login

这个函数做了以下几件事:

  • 它确保用户在访问任何一门课程或活动时都是已经登录的(未登录的用户不能进入任何课程)
  • 用户是否以访客身份登录
  • 验证用户是否具有访问隐藏的课程和活动的权限
  • 验证访问具有experimental groupmembersonly 权限的内容
  • 验证用户是否已选课或者具有'moodle/course:view'权限或者是在访问一些允许访客浏览的内容
  • 添加用户访问该课程的log记录

require_course_login()

这个函数应该只用于活动(activities)中,它会允许用户读取首页的内容而不会在log日志中记录。例如浏览资源文件、阅读词条列表等等。

isguestuser(), isloggedin() and is_siteadmin()

这些函数在过去需要首先限制特殊账户的访问。现在已经不需要了。因为任何具有权限或者有风险的权限都已经在has_capability()中自动了规避了这些用户。

强烈建议在活动(activity)模块中使用 is_siteadmin(),否则请务必准确地使用权限和选课信息。

is_guest(), is_viewing() and is_enrolled()

为了访问课程的数据,这些函数中至少要有一个返回true

  • is_enrolled(): 用户在user_enrolments表中有活动记录
  • is_viewing(): 用户具有’moodle/course:view’权限(可以访问,但不是参与者)
  • is_guest(): 访客用户被一些课程模块允许暂时访问

get_users_by_capability()

它会返回具有某种权限的所有用户的列表。它会忽略选课信息,因此只应在课程上下文之上被使用。