ZF2 / doctrine ORM认证不同的实体

时间:2015-03-11 11:39:59

标签: authentication orm doctrine-orm zend-framework2

在我的应用程序(ZF2 / ORM)中我有3个实体(具有单表继承)

  

用户

     

所有者扩展用户

     

代理扩展用户

我想使用3个实体进行一次身份验证(登录) doctrine.authenticationservice.orm_default

module.config.php

 //other doctrine config 
    'authentication' => array(
        'orm_default' => array(
            'object_manager' => 'Doctrine\ORM\EntityManager',
            'identity_class' => 'Application\Entity\User',
            'identity_property' => 'email',
            'credential_property' => 'password',
            'credential_callable' => function(User $user, $passwordGiven) {
                return $user->getPassword() == md5($passwordGiven);
            },
        ),
    ),

和登录过程

// LoginController.php

// ..data validation 
            $this->authService = $this->getServiceLocator()->get('doctrine.authenticationservice.orm_default');
            $AuthAdapter = $this->authService->getAdapter();
            $AuthAdapter->setIdentity($this->request->getPost('email'));
            $AuthAdapter->setCredential(md5($this->request->getPost('password')));
            $result = $this->authService->authenticate();

            if($result->isValid()){
                $identity = $result->getIdentity();
                //continue                   
            }

如何在不关心对象类型的情况下完成此过程, 当我尝试使用代理的电子邮件登录时,我收到此错误

  

捕获致命错误:传递给Application \ Module :: {closure}()的参数1必须是User的实例,Application \ Entity \ Owner的实例

1 个答案:

答案 0 :(得分:2)

您提到的错误是由于类型提示:

function(User $user) {

这让我相信你的配置文件中缺少名称空间声明;在这种情况下,您可以添加它或使用FQCN。

function(\Application\Entity\User $user) {

尽管如此,我认为这不是问题。您只能使用doctrine身份验证定义一个“identity_class”(适配器将使用该身份验证从实体管理器加载实体)。如果您有多个实体类,则无法使用一个适配器测试每个实体类。

但是,配置实际上只是创建一个新的身份验证适配器,特别是DoctrineModule\Authentication\Adapter\ObjectRepository。一种解决方案是创建多个ObjectRepository适配器,每个适配器具有不同实体的正确配置,然后在authenticate()上调用Zend\Authentication\AuthenticationService时循环遍历每个适配器。

例如:

public function methodUsedToAutheticate($username, $password)
{
    // Assume we have an array of configured adapters in an array
    foreach($adapters as $adapter) {

        $adapter->setIdentity($username);
        $adapter->setCredential($password);

        // Authenticate using the new adapter
        $result = $authService->authenticate($adapter);

        if ($result->isValid()) {
            // auth success
            break;
        }
    }
    return $result; // auth failed
}

如前所述,doctrine配置不允许使用多个适配器,因此您需要手动创建它们并删除当前配置。

另一个例子

public function getServiceConfig()
{
    return [
        'factories' => [
            'MyServiceThatDoesTheAuthetication' => function($sm) {

                $service = new MyServiceThatDoesTheAuthetication();

                // Assume some kind of api to add multiple adapters
                $service->addAuthAdapter($sm->get('AuthAdapterUser'));
                $service->addAuthAdapter($sm->get('AuthAdapterOwner'));
                $service->addAuthAdapter($sm->get('AuthAdapterAgent'));

                return $service;
            },
            'AuthAdapterAgent' => function($sm) {
                return new DoctrineModule\Authentication\Adapter\ObjectRepository(array(
                    'object_manager'      => $sm->get('ObjectManager'),
                    'identity_class'      => 'Application\Entity\Agent',
                    'identity_property'   => 'email',
                    'credential_property' => 'password'
                ));
            },
            'AuthAdapterOwner' => function($sm) {
                return new DoctrineModule\Authentication\Adapter\ObjectRepository(array(
                    'object_manager'      => $sm->get('ObjectManager'),
                    'identity_class'      => 'Application\Entity\Owner',
                    'identity_property'   => 'email',
                    'credential_property' => 'password'
                ));
            },
            // etc...
        ],
    ];
}

希望这能为您提供一些必要的想法。

最后,如果您考虑其他模块,ZfcUser already has a 'chainable adapter'实际执行上述操作(但使用事件管理器),那么即使您不使用它也可能值得一看。