ZF2 - BjyAuthorize - 如何从数据库中获取规则和保护

Nis*_*ana 5 doctrine zend-db zend-framework2 bjyauthorize

我正在使用BjyAuthorize和Zend Framework2来实现授权,并且能够成功地集成来自数据库的角色.现在我想从数据库表中获取规则和保护.我怎样才能做到这一点?

Den*_*nis 7

这里最简单的方法和"诀窍"是:

  1. 将规则和保护采用与示例配置中显示的相同的数组格式.因此,在从数据库中读取记录后,无论您的原始数据库数据是什么格式,都要处理它以匹配与配置中相同的保护格式.(我的回答详细介绍了如何使用Doctrine ORM,但也应该让您了解其他数据库引擎.只需用您的fave数据库引擎替换"DB read"操作)

  2. 将您已编写的规则注入BjyAuthorize所需的正确格式(因为您已经这样做了)BjyAuthorize\Guard\Controller,从内部注入YOUR_MODULE_NAME\Factory\DoctrineControllerGuardAdapterFactory.Bjy的控制器将处理规则,好像这些规则来自配置*,并且不怀疑任何差异.

  3. 退后一步,享受吧!

这是您需要在自己的模块中编写的构造:

namespace YOUR_MODULE_NAME\Factory;

/**
 * See "How and where exactly to register the factory" in ZF2 config
 * below in my answer.
 */
class [Custom]ControllerGuardAdapterFactory 
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        /**
         * Retrieve your rules from favorive DB engine (or anything)
         *
         * (You may use $serviceLocator to get config for you DB engine)
         * (You may use $serviceLocator to get your DB engine)
         * (You may use $serviceLocator to get ORM Entity for your DB engine)
         * (Or you may hack your DB connection and retrieval in some other way)
         *
         * Hell, you may read them from a text file using PHP's file() method
         * and not use $serviceLocator at all
         *
         * You may hardcode the rules yourself right here for all that matters
         */            
        $rules = ... //array(...);


        /** 
         * Inject them into Bjy's Controller
         *
         * Rules must be in the same format as in Bjy config, or it will puke.
         * See how ['guards'][\BjyAuthorize\Guard\Controller::class] is constructed 
         * in Bjy configuration for an example
         */             
        return new \BjyAuthorize\Guard\Controller($rules, $serviceLocator); 
    }
}
Run Code Online (Sandbox Code Playgroud)

现在观察并观察这是多么令人难以置信的复杂性!(以Bjy自己的机制为模型)

这主要是ZF2,OO和Bjy"配置地狱",伙计们,没有什么特别的.欢迎来到ZF2和Bjy以及ORM配置地狱.别客气.

详细解答 - 如何实施?

编写一个适配器工厂,它从数据库中读取规则,然后将它们注入BjyAuthorize的Controller Guard.效果将与读取规则的效果相同['guards'][\BjyAuthorize\Guard\Controller::class]

什么?

该方法BjyAuthorize的控制器卫队的工作原理是它需要的规则在一定的格式(指定格式['guards']['BjyAuthorize\Guard\Controller']),然后使用这些规则来填充ACL.它还会根据您的规则计算资源,并将这些资源加载到ACL中.如果没有,您将不得不编写自己的资源提供程序来执行此操作.

所以任务变成:

  • 从数据库加载规则并将规则转换为BjyAuthorize期望的格式.这可以在您自己的Rule Provider中完成,就像这个一样.
  • 您可以使用工厂从module.config.php文件加载特定的数据库和存储类配置数组.我把我放在了['guards']['YOUR_MODULE_NAME_controller_guard_adapter'].
'guards' => array(
        'YOUR_MODULE_NAME_controller_guard_adapter' => array(
            'object_manager' => 'doctrine.entity_manager.orm_default',
            'rule_entity_class' => 'YOUR_MODULE_NAME\Entity\ObjectRepositoryProvider'
        )
)
Run Code Online (Sandbox Code Playgroud)

示例实现细节(来自评论中的Q/A)

更多关于"将规则注入控制器"的最后一点.基本上有两个步骤:1)确保你已经(或将)以某种方式生成你的规则(这是艰难的一步).2)将这些规则注入控制器(这是更简单的步骤).实际注射是这样完成的

$rules = __MAGIC__;  //get rules out of somewhere, somehow.
return new Controller($rules, $serviceLocator); //$rules injection point
Run Code Online (Sandbox Code Playgroud)

请参阅下面的代码块以了解我自己的实现,其中块中的最后一行是我在上面给出的行.

namespace YOUR_MODULE_NAME\Factory;

use BjyAuthorize\Exception\InvalidArgumentException;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use YOUR_MODULE_NAME\Provider\Rule\DoctrineRuleProvider;    //this one's your own
use BjyAuthorize\Guard\Controller;

class DoctrineControllerGuardAdapterFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        //just setting up our config, move along move along...
        $config = $serviceLocator->get('Config');
        $config = $config['bjyauthorize'];

        //making sure we have proper entries in our config... 
        //move along "nothing to see" here....
        if (! isset($config['guards']['YOUR_MODULE_NAME_controller_guard_adapter'])) {
            throw new InvalidArgumentException(
                'Config for "YOUR_MODULE_NAME_controller_guard_adapter" not set'
            );
        }

        //yep all is well we load our own module config here
        $providerConfig = $config['guards']['YOUR_MODULE_NAME_controller_guard_adapter'];

        //more specific checks on config
        if (! isset($providerConfig['rule_entity_class'])) {
            throw new InvalidArgumentException('rule_entity_class not set in the YOUR_MODULE_NAME guards config.');
        }

        if (! isset($providerConfig['object_manager'])) {
            throw new InvalidArgumentException('object_manager not set in the YOUR_MODULE_NAME guards config.');
        }

        /* @var $objectManager \Doctrine\Common\Persistence\ObjectManager */
        $objectManager = $serviceLocator->get($providerConfig['object_manager']);

        //orp -- object repository provider
        //here we get our class that preps the object repository for us
        $orp=new DoctrineRuleProvider($objectManager->getRepository($providerConfig['rule_entity_class']));

        //here we pull the rules out of that object we've created above
        //rules are in the same format BjyAuthorize expects
        $rules=$orp->getRules();

        //here pass our rules to BjyAuthorize's own Guard Controller.  
        //It will not know the difference if we got the rules from Config or from Doctrine or elsewhere,  
        //as long as $rules are in the form it expects.
        return new Controller($rules, $serviceLocator); 
    }
}
Run Code Online (Sandbox Code Playgroud)

DoctrineRuleProvider

namespace YOUR_MODULE_NAME\Provider\Rule;

use Doctrine\Common\Persistence\ObjectRepository;
use BjyAuthorize\Provider\Rule\ProviderInterface;

/**
 * Guard provider based on a {@see \Doctrine\Common\Persistence\ObjectRepository}
 */
class DoctrineRuleProvider implements ProviderInterface
{
    /**
     * @var \Doctrine\Common\Persistence\ObjectRepository
     */
    protected $objectRepository;

    /**
     * @param \Doctrine\Common\Persistence\ObjectRepository $objectRepository            
     */
    public function __construct(ObjectRepository $objectRepository)
    {
        $this->objectRepository = $objectRepository;
    }

    /**
     * Here we read rules from DB and put them into an a form that BjyAuthorize's Controller.php understands
     */
    public function getRules()
    {
        //read from object store a set of (role, controller, action) 
        $result = $this->objectRepository->findAll();

        //transform to object BjyAuthorize will understand
        $rules = array();
        foreach ($result as $key => $rule)
        {
            $role=$rule->getRole();
            $controller=$rule->getController();
            $action=$rule->getAction();            

            if ($action==='all')    //action is ommitted
            {
                $rules[$controller]['roles'][] = $role;
                $rules[$controller]['controller'] = array($controller);
            }
            else
            {
                $rules[$controller.':'.$action]['roles'][]=$role;
                $rules[$controller.':'.$action]['controller']=array($controller);
                $rules[$controller.':'.$action]['action']=array($action);
            }                       
        }    

        return array_values($rules);
    }
}
Run Code Online (Sandbox Code Playgroud)

问:如何以及在何处注册工厂 DoctrineControllerGuardAdapterFactory

答:试试这条路: module\YOUR_MODULE_NAME\config\module.config.php并且有

'service_manager' => array(
    'factories' => array(
        'YOUR_MODULE_NAME_controller_guard_adapter' => \YOUR_MODULE_NAME\Factory\DoctrineControllerGuardAdapterFactory::class
    )
)
Run Code Online (Sandbox Code Playgroud)
  • 注意: YOUR_MODULE_NAME.=>标志左边的东西是"钥匙",可以是你想要的任何东西.Bjy中的约定是它类似于实际的类名和路径.而右边的东西=>是要使用此键调用的类的实际完全限定名称空间.


Sam*_*Sam 1

基本上你必须自己写Provider

看看不同的RoleProvider。每个都RoleProvider实现了Provider\Role\ProviderInterface. 当您想要实施守卫和规则时,也必须做同样的事情。您进入特定目录Provider\RuleProvider\Resource检查特定的ProviderInterface.

这样你就可以编写自己的类来实现接口,然后通过配置告诉 BjyAuthorize 使用你的提供者类。

就 Guards 而言,我确实相信还不可能从数据库创建它们。您必须修改/PR 模块本身才能实现这一点。