ZF2/doctrine ORM认证不同的Entity

ZF2 / doctrine ORM authentication different Entity

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

User

Owner extends User

Agent extends User

我想为 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                   
            }

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

Catchable fatal error: Argument 1 passed to Application\Module::{closure}() must be an instance of User, instance of Application\Entity\Owner given

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

function(User $user) {

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

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

不过,我认为这实际上不是问题所在。您只能定义一个 'identity_class' 与原则身份验证(适配器将使用它从实体管理器加载实体)。如果您有多个实体 类,则无法使用一个适配器测试每个实体。

但是,配置实际上只是创建一个新的身份验证适配器,具体来说 DoctrineModule\Authentication\Adapter\ObjectRepository。一种解决方案是创建多个 ObjectRepository 适配器,每个适配器都具有针对不同实体的正确配置,然后在 Zend\Authentication\AuthenticationService.

上调用 authenticate() 时循环遍历每个适配器

例如:

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
}

如前所述,原则配置不允许超过一个适配器,因此您需要手动创建它们并删除当前配置。

另一个例子

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' 实际上执行上述操作(但使用事件管理器),因此即使您不使用它也可能值得一看。