-1

我正在开发一个完全出于娱乐和教育目的的自定义框架。我已经阅读了这个关于如何实现权限的问题,我喜欢这些答案;使用装饰器模式和/或根据调度程序的 URL 检查权限。

我的问题是应该如何生成权限白名单?我不希望我的控制器中的每个方法都需要执行权限,因此我可以使用特殊的命名约定,例如在方法名称前加上“x”:

class CalendarController
{
    public function index($year = null, $month = null, $day = null)
    {
        // display calendar (no permission needed)
    }

    public function xAddEvent()
    {
        // display form to add event (permission required)
    }

    public function xAddEventSubmit()
    {
        // submit form to add event (permission required)
    }
}

然后我可以编写一个脚本来遍历我的所有控制器并返回 x 方法,给我分配给不同角色的权限列表。

另一种选择可能是将权限硬编码为每个控制器的属性,例如:

class CalendarController
{
    public $permissions = array('addEvent',
                                'addEventSubmit');

    public function index($year = null, $month = null, $day = null)
    {
        // display calendar (no permission needed)
    }


    public function addEvent()
    {
        // display form to add event (permission required)
    }

    public function addEventSubmit()
    {
        // submit form to add event (permission required)
    }
}

有没有更好的选择或者我在正确的轨道上?

4

3 回答 3

1

你有没有想过方法重载?这是一个非常简单的例子。基本上,如果找不到__call()函数,则使用该函数捕获它。然后,您可以进行权限检查并调用正确的私有或受保护方法。

class CalendarController
{
    public function index($year = null, $month = null, $day = null)
    {
        // display calendar (no permission needed)
    }

    public function __call($name, $arguments)
    {
        // do your permission checks here
        if ($name == 'addEvent' && $this->hasPermission()) {
            return $this->_addEvent($arguments);
        }

        return false;
    }

    protected function _addEvent($params) {

    }
}
于 2013-05-02T20:41:52.727 回答
1

注意:这主要是对我在链接文章中提供的解决方案的扩展。我不会评论hakre的答案。

据我了解您的问题,问题基本上是您不想分别为每种方法设置访问权限。

选项1:不装饰

在涉及到Decorator的解决方案中,好处之一是,当您使用安全类(例如Controller,尽管它可以是应用程序的任何部分)时,您不需要知道它已被修饰。因此,如果您有一些任何人都应该可以完全访问的控制器,那么您可以不装饰它们。

这种方法很可能需要负责控制器实例化的工厂拥有一些应该或不应该包装在装饰器中的控制器列表。因为这总是需要一个if声明来查阅列表,所以我个人认为这仅适用于您调用更多一种方法的实例(在我的情况下,它将不包括控制器)。

选项 2:通配符和白名单

解决此问题的另一种方法是利用您实际检查授权的方式。

$command = [ get_class($this->target), $method ];

这是被检查的令牌。这意味着 ACL 不仅接收方法的名称,还接收完整的类名(包括命名空间,顺便说一句)。它使您有机会创建一个包含类名和方法名的规则列表。类似于以下内容:

Controllers\Identification::*  anonymous
Controllers\*::*               admin
Controllers\Users::view        authenticated
Controllers\Users::remove      manager
Controllers\Users::add         manager

这个想法是您保存一些配置,您可以在其中定义所有允许的交互。ACL 在列表中向下,检查用户的组,并在第一次匹配时返回结果(在示例中,管理员可以访问除登录页面之外的所有内容,仅允许未经身份验证的用户使用)。再说一次,这个特定的示例将取决于您至少实现部分组包含组功能。

我还要重申,您应该只为此使用白名单。如果您忘记允许管理员删除用户,则不会增加任何重大风险,但是,如果您忘记拒绝用户删除其他用户,则在使用基于黑名单的授权时可能是一个严重错误。

我的两分钱

于 2013-05-04T21:00:34.783 回答
0

我建议查看其他框架以了解它们如何实施限制。例如,yii 根据请求的特定操作以及用户是否具有特定级别的权限来实施访问限制。我强烈推荐 RBAC(http://en.wikipedia.org/wiki/Role-based_access_control

Yii 示例:

public function accessRules()
{
    return array(
        array('allow',  // allow all users to perform 'list' and 'show' actions
            'actions'=>array('list','show'),
            'users'=>array('*'),
        ),
        array('allow', // allow authenticated user to perform 'create' and 'update' actions
            'actions'=>array('create','update'),
            'users'=>array('@'),
        ),
        array('allow', // allow admin user to perform 'admin' and 'delete' actions
            'actions'=>array('admin','delete'),
            'users'=>array('admin'),
        ),
        array('deny',  // deny all users
            'users'=>array('*'),
        ),
    );
}

他们还实现了过滤器,告诉我们某些类型的 HTTP 请求必须请求某些操作。以下示例说明为了运行创建操作,HTTP 请求必须是 POST。

public function filters()
{
    return array(
        'accessControl', // perform access control for CRUD operations
        'postOnly + create', // we only allow create via POST request
    );
}

资源:http ://www.larryullman.com/2010/01/14/yii-framework-access-control-lists/

另见:http ://www.yiiframework.com/wiki/169/configuring-controller-access-rules-to-default-deny/

于 2013-05-02T20:31:06.190 回答