Архитектура контроля доступа в приложении PHP - PullRequest
0 голосов
/ 09 февраля 2012

Я пытаюсь выяснить, как ограничить доступ к определенным ресурсам в проекте PHP, над которым я сейчас работаю. Я искал существующие решения, но ни одно из них действительно не соответствует тому, что мне нужно (например, Zend_Acl).

Теперь я придумал что-то вроде этого: (Конечно, это очень, очень упрощено. Никаких исключений или чего-то еще. Просто достаточно, чтобы донести смысл)

class Access {
    protected $_context;
    protected $_handlers;
    public function __construct($context) {
        $this->_context = $context;
    }
    public static function registerHandler(Access_Handler $handler) {
        $key = $handler->getContextType().'/'.$handler->getResourceType();
        self::$_handlers[$key] = $handler;
    }
    public function isAllowed($resource) {
        return $this->getHandler($resource)->isAllowed($this->_context, $resource);
    }
    public function getHandler($resource) {
        // Look for and return the appropriate handler for the combination of 
        // $context and $resource
    }
}

abstract class Access_Handler {
    $_contextType;
    $_resourceType;
    abstract public function isAllowed();
}

class Access_Handler_UserInvoice extends Access_Handler {
    $_contextType = 'User';
    $_resourceType = 'Invoice';
    public function isAllowed($user, $invoice) {
        if($invoice->user_id === $user->id) {
            return true;
        }
        return false;
    }
}

Я бы тогда сделал что-то подобное в моей загрузочной программе:

protected function $_initAccessHandlers() {
    Access::registerHandler(new Access_Handler_UserInvoice());
}

И в моем контроллере (потому что я слышал , это то место, где вы должны поставить свой контроль доступа) У меня было бы что-то вроде этого:

class InvoiceController {
    public function viewAction() {
        // $this->me is of type User
        $access = new Access($this->me);
        if($access->isAllowed($this->invoice)) {
            // ...
        }
    }
}

Я не проверял код, поэтому могут быть опечатки или другие ошибки, но я думаю, вы поняли суть. Кроме того, в действительности я бы, вероятно, реализовал Access как Singleton или Multiton, но мой вопрос не в этом.

Это правильный способ сделать это? Это кажется мне таким естественным, но потом я задаюсь вопросом, почему никто другой не делает это таким образом.

Мой стек разработки - PHP / MySQL / Zend Framework / Doctrine.

1 Ответ

1 голос
/ 10 февраля 2012

С помощью Zend_Acl вы будете выполнять основное управление, например:

$acl = new Zend_Acl();
$acl->add(new Zend_Acl_Resource('article'));
$acl->addRole(new Zend_Acl_Role('author'));
$acl->deny();
$acl->allow('author', 'article', array('list'));

Тогда вы можете использовать утверждения, чтобы делать то, что вы хотите:

$user = Zend_Auth::getInstance()->getIdentity();
$assertion = new My_Acl_Assertion_ArticleEditCheck($user);
$acl->allow('author', 'article', 'edit', $assertion);

Вы можете вместо передачи пользовательского объекта утверждению реализовать его как внутреннее свойство, а также при необходимости работать с параметрами запроса.

Ссылки:

http://framework.zend.com/manual/en/zend.acl.advanced.html

Динамический пользовательский ACL в Zend Framework?

Для более сложного использования утверждений, смотрите:

http://www.aviblock.com/blog/2009/03/19/acl-in-zend-framework/

http://ralphschindler.com/2009/08/13/dynamic-assertions-for-zend_acl-in-zf

...