Skip to content

Tutorial.Authentication Management I.zh_cn

liuchuangww edited this page Jul 4, 2013 · 5 revisions

English

  1. 引言

权限控制在软件系统里非常重要,它能防止一些重要的信息透露给非相关的用户或管理员,从而保证系统的安全。Pi Engine也为开发者和用户提供了权限开发与操作,对于管理员,可以通过后台配置为不同角色的管理员分配相应的权限,对于开发者,Pi Engine提供了Pi\Acl\Acl类来进行权限功能的开发。

1.1 Pi权限机制简介

在Pi Engine中,权限是作为一个资源,即Acl Resource,当初始化系统时,这个资源将会被载入,用于用户权限判定的方法checkAccess()会被附加到dispatch事件驱动里。同时这个方法的优先级也被设置为最高,这能够保证在访问到页面之前先判定用户的权限。

fig8-1

图8-1 载入Acl资源源码

而在checkAccess()方法里,Pi Engine会去检查请求的用户对当前页面是否有访问权限,若没有则会去跳转到禁止访问的流程。因此在Pi Engine后台配置权限时,Pi Engine可以决定用户能否看到相关的系统或模块页面(Controller & Action),但对于模块内容某一资源的权限,后台可以配置,但Pi Engine无法决定是否显示这个资源,这需要开发者对模块进行相应开发。

Pi Engine提供了几个数据表用于保存角色、资源以及角色和资源的关系数据,这些数据表不需要开发者直接操作,Pi Engine封装了Pi\Acl\Acl类来操作这些数据表,而在checkAccess()方法里,也是通过Acl实例来判断用户权限。关于更多的Acl类的使用可参考Pi Engine文档。

1.2 角色、资源及权限

在使用权限时会涉及到这几个概念:角色、资源以及角色与资源间的对应关系,即权限。这里介绍下Pi Engine里这几个概念的定义。

角色也就是一个帐号在系统里的身份,目前Pi Engine在前后的角色是独立的,即一个帐号在前后台分别对应了一个角色,这两个角色之间没有联系。Pi Engine在前后台都定义了一些默认角色,如前台有:

  • member
  • guest
  • pending
  • banned

后台为:

  • staff
  • moderator
  • editor
  • manager

Pi Engine支持角色的单继承和多继承,如在后台角色中,moderator继承自staff、manager继承自moderator和editor。而模块也可以定义角色,这些角色也是公有角色。

资源可理解为用户能获取到的任何东西,大到一个页面,小到一个按钮或者是一个文字。因此资源可以是一个页面,一般用Controller & Action来定义,或者是用一个字符串描述来指代一个资源,比如我们用publish-article-edit来指代页面上的edit按钮,角色与publish-article-edit对应的关系为denied时,说明不允许该用户操作此按钮。

权限就是定义角色允许或禁止访问某一资源。在Pi Engine里默认是角色禁止访问所有模块资源,如果需要更改,可用超级管理员帐号去后台修改。

在Pi Engine中,父类角色的allow权限无条件往后派生。即父类若对一个资源是允许的,不管子类如何修改权限,它对该资源都是允许的。这可以用下图来示意:

fig8-2

图8-2 Pi中对Allow权限的继承

  1. 创建角色、资源及权限

上面的介绍里,我们已经提到过,角色、资源等数据都保存在数据表里,并且在模块里也可以定义这些信息,这部分我们将介绍如何创建角色、资源以及关联角色和资源。同时也将介绍如何将一个资源定义为页面资源或字符串资源。

2.1 创建角色

模块里角色的创建是通过配置完成的,这个配置就是acl.php,在安装的时候角色信息将被写入到core_acl_role表里。下面代码介绍了如何创建角色并指定义角色间的继承关系:

<?php
return array(
    'roles'     => array(
        // Case 1
        'frontRole1'   => array(
            'title'       => __('Front role'),
        ),
        // Case 2
        'childRole1'   => array(
            'title'       => __('Role have one parent'),
            'section'     => 'admin',
            'parents'     => array('editor'),
        ),
        // Case 3
        'parent1'      => array(
            'title'       => __('Parent1'),
            'section'     => 'admin',
            'parents'     => array('staff'),
        ),
        'parent2'      => array(
            'title'       => __('Parent2'),
            'section'     => 'admin',
        ),
        'childRole2'   => array(
            'title'       => __('Role have two parent'),
            'section'     => 'admin',
            'parents'     => array('parent1', 'parent2'),
        ),
    ),
);

角色的定义在role.php配置里以roles字段标识,roles数组里的每一个子数组就是一个角色。这里需要注意的是,这里子数组的键值不仅在该模块里唯一,还不能与已经安装的模块角色的name相同。在roles数组里我们采用了三个例子说明角色的定义。

在例子里,frontRole1, childRole1, parent1等就是角色唯一名称。titile字段就是模块名,用于显示,在例子中我们写成了描述的形式,实际情况下最好用比较简短的单个词来表示。例子创建了一个前台角色,这个角色无父类。section字段用来表示角色为前台或后台角色,front为前台,admin为后台,如果没有标志默认为前台,如Case 1所示。

Case 2定义了一个后台角色,这个后台角色继承自系统后台的editor角色,角色的继承用parents字段来标识,父类角色的name以数组的形式赋给该字段。

Case 3定义了两个后台角色,其中一个角色继承自系统角色staff,另一个无父角色,接着又定义了一个子角色继承自这两个角色,即多继承,多个角色也同样以数组的形式赋给parents字段。在这个例子中,childRole2间接地继承自staff角色。

2.2 创建资源

资源的创建同样也是要acl.php配置里完成的,而资源是以resources字段来标识。而资源间也允许继承,下面的代码介绍了如何定义一个资源以及资源间的继承:

<?php
return array(
    'roles'     => array(
        ...
    ),

    'resources' => array(
        // Case 1
        'front'        => array(
            'module-resource1'   => array(
                'module'      => 'demo',
                'title'       => __('Resource1'),
            ),
        ),
        // Case 2
        'admin'        => array(
            'module-resource2'   => array(
                'module'      => 'demo',
                'title'       => __('Resource2'),
            ),
            'module-resource3'   => array(
                'module'      => 'demo',
                'title'       => __('Resource3'),
                'parent'      => 'module-resource2',
            ),
        ),
    ),
);

在resource字段里,分别用front和admin来区分该资源为前台或后台资源。front和admin数组里的每一个子数组就是一个资源。其中module-resource1, module-resource2就是资源名,这个资源名在整个系统里也是唯一的。在每个资源数组里,module字段表示该资源所属的模块;title为资源名,用于显示;parent定义了该资源的父资源。Case 2就定义了一个资源module-resource2以及其子资源module-resource3。

上述代码里定义的资源都是字符串资源,如果要定义一个页面资源,需要添加一个page.php配置,并关联Controller & Action和acl.php里的资源。page.php另外的功能是用来定义某一个Controller & Action的缓存、是否支持组装,这部分可以参考Pi Engine的文档。在page.php配置里添加权限相关的代码如下:

<?php
return array(
    'front'    => array(

    ),
    'admin'    => array(
        // Case 1
        array(
            'controller'  => 'index',
            'permission'  => array(
                'parent'      => 'module-resource2',
            ),
        ),
        // Case 2
        array(
            'title'       => __('Page 1'),
            'module'      => 'demo',
            'controller'  => 'test1',
            'permission'  => array(
                'access'      => array(
                    'staff'      => 1,
                    'parent1'    => 0,
                ),
            ),
        ),
    ),
    // Case 3
    'exception'  => array(
        array(
            'controller'  => 'ajax',
        ),
    ),
);

在page.php里同样以front和admin来区分前后台的页面,每一个子数组就是一个页面,以Controller/Action来表示。例子1中,我们定义了一个Controller资源,同时用permission字段来标识角色对这个资源的权限,这里用parent字段将这个资源继承自acl.php配置里定义的字符串资源module-resource2,这样这个资源将与module-resource2资源拥有相同的权限。因此以后就可以用module-resource2来作为这个controller资源的资源名。

例子2也定义了一个页面资源及其权限(权限将在下一节讲),所不同的是,这里直接在permission数组里定义了权限,也就是这个controller资源没有与acl.php配置里的字符串资源关联,因此这个资源的资源名就是这种形式:

array(
    'module'   => 'demo',
    'controller' => 'test',
);

在很多时候,我们在后台会有一些AJAX调用,这些调用我们希望默认就能访问,例子3就给出解决方法,用exception字段告诉系统这个controller或action不需要走权限判定流程。这样AjaxController在任何情况下都可以被访问。

2.3 创建权限

权限的定义也同样在acl.php配置里完成,用户对资源的访问权限主要以access字段来定义:

<?php
return array(
    ...
    'resources' => array(
        ...
        'admin'        => array(
            'module-resource2'   => array(
                'module'      => 'demo',
                'title'       => __('Resource2'),
                'access'      => array(
                    'staff'      => 1,
                    'parent1'    => 0,
                ),
            ),
            ...
        ),
    ),
);

上述代码为module-resource2定义了角色的访问权限,在module-resource2资源里以access字段标识,access数组里,键值为角色唯一名称,值为0或1,为0时说明不允许该角色访问,为1时为允许,若不标识,默认为0。

  • 禁止导航资源时,隐藏导航

在后台Operation页里,一个导航项(如List页)会对应一个页面(如IndexController/listAction),这个页面也是一个资源(如资源名为list-items),当我们禁止某角色访问该资源时,当然也希望该角色在Operation页里看不到List页这个导航项,因此就需要在导航配置navigation.php里作些修改:

return array(
    'admin'   => array(
        'pagea'   => array(
            ...
            'controller' => 'index',
            'action'     => 'list',
            'resource'   => array(
                'resource'   => 'list-items',
            ),
        ),
        ...
    ),
    ...
);

代码里用resource字段来标识,resource数组里也用resource字段标识资源名,list-items就是在acl配置里定义的资源名。

**注意:**这里定义了两个配置文件acl.php和page.php,由于page.php里引用到acl.php,因此安装时需要先安装acl.php配置,即在module.php里,acl.php的引用要在page.php之前。

[Tutorial.Authentication Management II](Tutorial.Authentication Management II.zh_cn)

Clone this wiki locally