我正在制作一个严格用于娱乐和教育目的的自定义框架。我已经阅读了this question关于如何实现权限的内容,我喜欢这些答案;使用装饰器模式和/或根据调度程序的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)
}
}
有没有更好的选择,还是我走在正确的轨道上?
答案 0 :(得分:1)
您有没有想过method overloading?这是一个非常简单的例子。基本上,如果找不到函数,则使用__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) {
}
}
答案 1 :(得分:1)
注意:这主要是我在链接文章中提供的解决方案的扩展。我不会对hakre的答案发表评论。
据我了解您的问题,问题基本上是您不希望单独为每个方法设置访问权限。
在解决方案中,涉及 Decorator ,其中一个好处是,当您使用安全类时(例如Controller
,虽然它可以是应用程序的任何部分) ,你不需要知道它已被装饰。因此,如果你有一些控制器应该完全可以被任何人访问,那么你可以不装饰它们。
这种方法很可能需要工厂负责实例化控制器,以便有一些应该或不应该包装在装饰器中的控制器列表。由于这总是需要一个if
语句来查阅列表,我个人会认为这仅适用于您调用更多方法的实例(在我的情况下,将排除控制器)。
解决此问题的另一种方法是利用您实际检查授权的方式。
$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在列表中向下,检查用户的组,并在第一次匹配时返回结果(在示例中,管理员可以访问除登录页面之外的所有内容,仅允许未经身份验证的用户使用)。然后,此特定示例将取决于您实现至少部分组包含组功能。
我还要重申,你应该只使用白名单。如果您忘记允许管理员删除用户,则不会增加重大风险,但是,如果您忘记拒绝用户删除其他用户,则在使用基于黑名单的授权时可能是一个严重的错误。
我的两分钱
答案 2 :(得分: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请求请求某些操作。以下示例指出,为了运行create操作,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/