如何在Web MVC应用程序中实现访问控制列表? [英] How can I implement an Access Control List in my Web MVC application?

查看:73
本文介绍了如何在Web MVC应用程序中实现访问控制列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

第一个问题

请,您能解释一下如何在MVC中实现最简单的ACL.

Please, could you explain me how simpliest ACL could be implemented in MVC.

这是在Controller中使用Acl的第一种方法...

Here is the first approach of using Acl in Controller...

<?php
class MyController extends Controller {

  public function myMethod() {        
    //It is just abstract code
    $acl = new Acl();
    $acl->setController('MyController');
    $acl->setMethod('myMethod');
    $acl->getRole();
    if (!$acl->allowed()) die("You're not allowed to do it!");
    ...    
  }

}
?>

这是一种非常糟糕的方法,它的缺点是我们必须将Acl代码添加到每个控制器的方法中,但是我们不需要任何其他依赖项!

It is very bad approach, and it's minus is that we have to add Acl piece of code into each controller's method, but we don't need any additional dependencies!

下一种方法是使所有控制器的方法private并将ACL代码添加到控制器的__call方法中.

Next approach is to make all controller's methods private and add ACL code into controller's __call method.

<?php
class MyController extends Controller {

  private function myMethod() {
    ...
  }

  public function __call($name, $params) {
    //It is just abstract code
    $acl = new Acl();
    $acl->setController(__CLASS__);
    $acl->setMethod($name);
    $acl->getRole();
    if (!$acl->allowed()) die("You're not allowed to do it!");
    ...   
  }

}
?>

比以前的代码更好,但主要缺点是...

It is better than previous code, but main minuses are...

  • 所有控制器的方法都应为私有
  • 我们必须将ACL代码添加到每个控制器的__call方法中.

下一种方法是将Acl代码放入父控制器中,但是我们仍然需要将所有子控制器的方法设为私有.

The next approach is to put Acl code into parent Controller, but we still need to keep all child controller's methods private.

解决方案是什么?最佳实践是什么? 我应该在哪里调用Acl函数来决定允许或禁止执行方法.

What is the solution? And what is the best practice? Where should I call Acl functions to decide allow or disallow method to be executed.

第二个问题

第二个问题是关于使用Acl获得角色的信息.假设我们有客人,用户和用户的朋友.用户具有查看其个人资料的访问权限,只有朋友可以查看.所有访客都无法查看此用户的个人资料.所以,这就是逻辑.

Second question is about getting role using Acl. Let's imagine that we have guests, users and user's friends. User have restricted access to viewing his profile that only friends can view it. All guests can't view this user's profile. So, here is the logic..

  • 我们必须确保被调用的方法是配置文件
  • 我们必须检测此个人资料的所有者
  • 我们必须检测出观看者是此个人资料的所有者,还是没有?
  • 我们必须阅读有关此配置文件的限制规则
  • 我们必须决定执行或不执行配置文件方法

主要问题是关于检测个人资料的所有者.我们只能通过执行模型的方法$ model-> getOwner()来检测谁是配置文件的所有者,但是Acl没有访问模型的权限.我们如何实现呢?

The main question is about detecting owner of profile. We can detect who is owner of profile only executing model's method $model->getOwner(), but Acl do not have access to model. How can we implement this?

我希望我的想法很明确.对不起,我的英语.

I hope that my thoughts are clear. Sorry for my English.

谢谢.

推荐答案

第一部分/答案(ACL实现)

以我的拙见,解决此问题的最佳方法是使用装饰器模式,基本上,这意味着您要拿起您的物体,并将其放在内部另一个物体,其作用类似于保护壳.这将不需要您扩展原始类.这是一个示例:

First part/answer (ACL implementation)

In my humble opinion, the best way to approach this would be to use decorator pattern, Basically, this means that you take your object, and place it inside another object, which will act like a protective shell. This would NOT require you to extend the original class. Here is an example:

class SecureContainer
{

    protected $target = null;
    protected $acl = null;

    public function __construct( $target, $acl )
    {
        $this->target = $target;
        $this->acl = $acl;
    }

    public function __call( $method, $arguments )
    {
        if ( 
             method_exists( $this->target, $method )
          && $this->acl->isAllowed( get_class($this->target), $method )
        ){
            return call_user_func_array( 
                array( $this->target, $method ),
                $arguments
            );
        }
    }

}

这就是您使用这种结构的方式:

And this would be how you use this sort of structure:

// assuming that you have two objects already: $currentUser and $controller
$acl = new AccessControlList( $currentUser );

$controller = new SecureContainer( $controller, $acl );
// you can execute all the methods you had in previous controller 
// only now they will be checked against ACL
$controller->actionIndex();

您可能会注意到,此解决方案具有以下优点:

As you might notice, this solution has several advantages:

  1. 包含可用于任何对象,而不仅限于Controller
  2. 的实例
  3. 检查授权发生在目标对象之外,这意味着:
    • 原始对象不负责访问控制,遵守 SRP
    • 当您获得权限被拒绝"时,您就没有被锁定在控制器内,更多选项
  1. containment can be used on any object, not just instances of Controller
  2. check for authorization happens outside the target object, which means that:
    • original object is not responsible for access control, adheres to SRP
    • when you get "permission denied", you are not locked inside a controller, more options

但是,此方法也存在一个主要问题-您无法本地检查安全对象的实现和接口(也适用于查找现有方法)或是否属于某些继承链.

But, there are one major issue with this method too - you cannot natively check if secured object implements and interface ( which also applies for looking up existing methods ) or is part of some inheritance chain.

在这种情况下,您应该认识到的主要区别是域对象(例如:Profile)本身包含有关所有者的详细信息.这意味着,您需要检查用户是否(以及在哪个级别)可以访问它,这将要求您更改此行:

In this case the main difference you should recognize is that you Domain Objects (in example: Profile) itself contains details about owner. This means, that for you to check, if (and at which level) user has access to it, it will require you to change this line:

$this->acl->isAllowed( get_class($this->target), $method )

基本上,您有两个选择:

Essentially you have two options:

$this->acl->isAllowed( get_class($this->target), $method )

  • 请求所有相关详细信息,并仅向ACL提供所需的内容,这也将使其对单元测试更加友好:

  • Request all the relevant details and provide the ACL only with what it needs, which will also make it a bit more unit-testing friendly:

    $command = array( get_class($this->target), $method );
    /* -- snip -- */
    $this->acl->isAllowed( $this->target->getPermissions(), $command )
    

  • 结合视频,可能会帮助您提出自己的实施方案:

    Couple videos that might help you to come up with your own implementation:

    • Inheritance, Polymorphism, & Testing
    • Don't Look For Things!

    您似乎对MVC中的模型有相当普遍的理解(完全错误). 模型不是类.如果您有名为FooBarModel的类或继承了AbstractModel的类,那么您做错了.

    You seem to have the quite common ( and completely wrong ) understanding of what Model in MVC is. Model is not a class. If you have class named FooBarModel or something that inherits AbstractModel then you are doing it wrong.

    在适当的MVC中,模型是一层,其中包含许多类.根据职责,大部分课程可以分为两组:

    In proper MVC the Model is a layer, which contains a lot of classes. Large part of the classes can be separated in two groups , based on the responsibility:

    (了解更多:此处这组类中的实例处理值的计算,检查不同的条件,实施销售规则并执行所有其余的事情,即所谓的业务逻辑".他们不知道数据的存储方式,存储位置或存储位置.

    Instances from this group of classes deal with computation of values, check for different conditions, implement sales rules and do all the rest what you would call "business logic". They have no clue how data is stored, where it is stored or even if storage exists in first place.

    域业务对象不依赖于数据库.创建发票时,数据来自哪里都没有关系.它可以来自SQL或来自远程REST API,甚至可以来自MSWord文档的屏幕截图.业务逻辑没有改变.

    Domain Business object do not depend on database. When you are creating an invoice, it does not matter where data comes from. It can be either from SQL or from a remote REST API, or even screenshot of a MSWord document. The business logic does no change.

    由这组类制成的实例有时称为数据访问对象.通常实现数据映射器模式的结构(不要与同名的ORM混淆...无关系) .这就是您的SQL语句所在的位置(或者您的DomDocument,因为您将其存储在XML中).

    Instances made from this group of classes are sometimes called Data Access Objects. Usually structures that implement Data Mapper pattern ( do not confuse with ORMs of same name .. no relation ). This is where your SQL statements would be (or maybe your DomDocument, because you store it in XML).

    除了两个主要部分外,还有一组实例/类应该被提及:

    Beside the two major parts, there is one more group of instances/classes, that should be mentioned:

    这是您和第三方的组件在其中发挥作用的地方.例如,您可以将身份验证"视为服务,可以由您自己的身份或某些外部代码提供.同样,邮件发件人"将是一项服务,它可以将某些域对象与PHPMailer或SwiftMailer或您自己的邮件发送者组件结合在一起.

    This is where your and 3rd party components come in play. For example, you can think of "authentication" as service, which can be provided by your own, or some external code. Also "mail sender" would be a service, which might knit together some domain object with a PHPMailer or SwiftMailer, or your own mail-sender component.

    服务的另一个来源是域和数据访问层的抽象.创建它们是为了简化控制器使用的代码.例如:创建新用户帐户可能需要使用多个域对象映射器.但是,通过使用服务,它将仅需要控制器中的一两行.

    Another source of services are abstraction on to on domain and data access layers. They are created to simplify the code used by controllers. For example: creating new user account might require to work with several domain objects and mappers. But, by using a service, it will need only one or two lines in the controller.

    在进行服务时,您必须记住的是,整个层应该是.服务中没有业务逻辑.它们只是在杂耍领域对象,组件和映射器.

    What you have to remember when making services, is that the whole layer is supposed to be thin. There is no business logic in services. They are only there to juggle domain object, components and mappers.

    它们共有的一件事是,服务不会以任何直接方式影响View层,并且具有一定程度的自治性,因此可以在MVC结构之外使用(并且经常退出)它们.本身.由于服务与应用程序其余部分之间的耦合度极低,因此这种自我维持的结构也使向其他框架/体系结构的迁移变得更加容易.

    One of things they all have in common would be that services do not affect the View layer in any direct way, and are autonomous to such an extent, that they can be ( and quit often - are ) used outside the MVC structure itself. Also such self-sustained structures make the migration to a different framework/architecture much easier, because of extremely low coupling between service and the rest of application.

    这篇关于如何在Web MVC应用程序中实现访问控制列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆