7.6 访问控制

现在我们已经验证了用户并且知道了分配给该用户的角色,我们可以使用这些信息得到此用户访问过的控制器、动作甚至是对象。

与验证和角色适配器一样,我们并不需要自己实例化访问-控制对象;已注册的Solar_User对象会自动建立一个$access属性。

7.6.1 适配器

Solar提供不同的适配器帮助你从不同的后端找出用户访问-控制信息。Solar现有的适配器如下:

[Note]Note

注意,这些适配器都是只读的。它们不会为你管理和创建访问控制列表,它们仅仅查找用户和角色的权限信息。

用户验证后的身份在登陆期间是不会发生变化的。但是,用户的访问控制在同一次会话中可能会发生变化;例如,登陆后,用户被提示身份由版主变为作者。因为这个原因,所以访问适配器在每次加载新页面时都会从存储后端重新读取控制列表。

Solar使用Solar_Access工厂类实例化适配器,所以你需要在配置文件中指定你在系统中想使用的适配器。你可以这样配置:

<?php
$config['Solar_Access'] = array(
    'adapter'    => 'Solar_Access_Adapter_File',
);

7.6.2 适配器配置

现在我们已经告诉工厂类要实例化哪个适配器了,我们还需要配置适配器本身。访问适配器比验证适配器容易配置得多,但是每个适配器有自己独有的配置。你可以点击下面的链接查看它们各自需要的配置。

例如,一个基于文件的且使用SYSTEM/config/access.txt文件中的访问控制列表的访问控制器,配置如下:

<?php
$config['Solar_Access_Adapter_Sql'] = array(
    'file'      => "$system/config/access.txt",
);

7.6.3 访问控制列表格式

访问控制列表每行只有一条记录,而每条记录又包含5个元素。

flag

(string) 本条记录允许('allow')访问或拒绝('deny')访问?

type

(string) 本条记录是基于用户的用户名('handle')还是用户的角色('role')亦或是某个特定对象的所有者('owner')?(要了解更多“所有权访问”的信息请查看下面的章节)。

name

(string) 如果记录类型是'handle',这会标识出被控制用户的用户名。这个元素有两个特殊的值:一个是'*',意味着“所有用户”(甚至是匿名或未验证用户);另一个是'+',意味着“所有*验证过*的用户”。

(string) 如果记录类型是'role',这会标识出被控制的用户角色。特殊值'*'表示“所有角色”。

(string) 如果记录类型是'owner',这个值不起任何作用。你可以留空或是把它设置为'*'。(要了解更多“所有权访问”的信息请查看下面的章节)。

class

(string) 本条访问控制记录适合于哪个类?(通常来说是一个页面控制器类)。特殊值'*'表示“所有类”。

action

(string) 本条记问控制器适合于哪个动作?(通常来说是一个页面控制器动作)。特殊值'*'表示“所有动作”。

这里有一个基于文件的访问控制列表示例:

# flag      type        name        class                   action
# ----      ----        ----        -----                   ------

# allow any user with an "admin" role access to all actions in all classes
allow       role        admin       *                       *

# allow all users access to the actionRead() method in all classes
allow       handle      *           *                       read

# allow only authenticated users access to actionComment() in all classes
allow       handle      +           *                       comment

# allow only authors to add new pages
allow       role        author      Vendor_App_Page         add

# allow any user with a "moderator" role acces to Vendor_App_Comments::actionDelete()
allow       role        moderator   Vendor_App_Comments     delete

# deny all users access to Vendor_App_Page::actionEdit() ...
deny        handle      *           Vendor_App_Page         edit

# ... except for user authenticated as "kornblum"
allow       handle      kornblum    Vendor_App_Page         edit
[Note]Note

控制列表是从头到尾执行的,所以后面的记录会覆盖前面的记录。

访问控制默认是拒绝的,所以如果文件中没有任何记录,所有控制都会提示“拒绝访问”。

7.6.4 使用方法

假设我们使用基于文件的访问适配器从文件中读取访问控制信息,上面列出的清单为文件内容。再假设用户'kornblum'已经登陆系统了;而且他在系统中只扮演一种角色(‘版主’)。

Solar_User对象内部含有Solar_Access_Adapter实例,所以当我们实例化它后,它会自动查询访问控制文件并从中获取用于用户'andy'的控制记录。之后我们可以使用Solar_Access_Adapter的方法判断'kornblum'是否有访问当前控制器和动作的权限。(别忘了,我们使用的是Solar_User对象,而不需要单独实例化一个访问控制适配器。)

<?php
$class = 'Vendor_App_Page';

$user = Solar_Registry::get('user');
$user->auth->handle; // 'kornblum'

$user->access->isAllowed($class, 'read'); // true
$user->access->isAllowed($class, 'comment'); // true (if not logged in, false)
$user->access->isAllowed($class, 'add'); // false (not an author)
$user->access->isAllowed($class, 'edit'); // true
$user->access->isAllowed($class, 'foobar'); // false (deny-by-default)