为了账号安全,请及时绑定邮箱和手机立即绑定

使用 2 个实现 UserInterface 的实体进行身份验证

使用 2 个实现 UserInterface 的实体进行身份验证

PHP
撒科打诨 2022-07-22 15:11:53
是否有可能有 2 个实体实现UserInterface?如何在我的警卫上使用它来使其在两个类中检查并使用相同的防火墙?这个想法是公司可以拥有CVTheque或共享它(CVTheque与 具有 OneToMany 关系Company)。我想拥有Candidate和User实体。CVTheque -> OneToMany -> 候选人用户 -> 多对一 -> 公司。Candidate并将User使用相同的登录表单在应用程序上进行身份验证。所以我不知道这是否可能以及如何在我的警卫身份验证器上实现这一点。Candidate根据连接用户的实例(或User),它们将被重定向到自己的仪表板。
查看完整描述

2 回答

?
莫回无

TA贡献1865条经验 获得超7个赞

最近处理了类似的情况。在我的例子中,刚刚创建了一个chain_provider来封装所有需要的实体:


providers:

    chain_provider:

        chain:

            providers: [provider_one, provider_two]

    provider_one:

        entity:

            class: App\Entity\ProviderOne

            property: username

    provider_two:

        entity:

            class: App\Entity\ProviderTwo

            property: email

security:

    firewalls:

        secured_area:

            # ...

            pattern: ^/login

            provider: chain_provider


查看完整回答
反对 回复 2022-07-22
?
ibeautiful

TA贡献1993条经验 获得超5个赞

我相信这是可能的,让我们采用基本的用户身份验证并尝试对其进行调整


<?php


namespace App\Security;


use App\Entity\User;

use Doctrine\ORM\EntityManagerInterface;

use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\Security\Core\Security;

use Symfony\Component\Security\Csrf\CsrfToken;

use Symfony\Component\EventDispatcher\GenericEvent;

use Symfony\Component\HttpFoundation\RedirectResponse;

use Symfony\Component\Security\Core\User\UserInterface;

use Symfony\Component\Security\Http\Util\TargetPathTrait;

use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;

use Symfony\Component\Security\Core\User\UserProviderInterface;

use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;

use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;

use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;

use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;


class LoginAuthenticator extends AbstractFormLoginAuthenticator

{

    use TargetPathTrait;


    private $entityManager;

    private $urlGenerator;

    private $csrfTokenManager;

    private $encoder;


    public function __construct(

        EntityManagerInterface $entityManager,

        UrlGeneratorInterface $urlGenerator,

        CsrfTokenManagerInterface $csrfTokenManager,

        UserPasswordEncoderInterface $encoder)

    {

        $this->entityManager = $entityManager;

        $this->urlGenerator = $urlGenerator;

        $this->csrfTokenManager = $csrfTokenManager;

        $this->encoder = $encoder;

        $this->eventDispatcher = $eventDispatcher;

    }


    public function supports(Request $request)

    {

        return (

            'login' === $request->attributes->get('_route')&& $request->isMethod('POST') // here you need to specify the other login route if you want to have 2 seperate ones

        );

    }


    public function getCredentials(Request $request)

    {

        $credentials = [

            'username' => $request->request->get('username'),

            'password' => $request->request->get('password'),

            'csrf_token' => $request->request->get('_csrf_token'),

        ];

        $request->getSession()->set(

            Security::LAST_USERNAME,

            $credentials['username']

        );


        return $credentials;

    }


    public function getUser($credentials, UserProviderInterface $userProvider)

    {

        $token = new CsrfToken('authenticate', $credentials['csrf_token']);

        if (!$this->csrfTokenManager->isTokenValid($token)) {

            throw new InvalidCsrfTokenException();

        }


        $user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);


        if (!$user) { // here look for user in the 2nd entity, if it will still be null throw the exception

            // fail authentication with a custom error

            throw new CustomUserMessageAuthenticationException('Username could not be found.');

        }


        return $user;

    }


    public function checkCredentials($credentials, UserInterface $user)

    {

        return $this->encoder->isPasswordValid($user, $credentials['password'], $user->getSalt());

    }


    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)

    {        

        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {

            return new RedirectResponse($targetPath);

        }


        return new RedirectResponse($this->urlGenerator->generate('account_index'));

    }


    protected function getLoginUrl()

    {

        return $this->urlGenerator->generate('login');

    }

}


大概就是这样,我们将身份验证器更改为支持2个路由(登录一个,登录两个),如果第一个实体与用户名和密码不匹配,请尝试在另一个实体中查找用户,您不妨添加一个隐藏输入或根据路由在请求侦听器中添加属性,使用 RequestStack 检索它,或者您想要指示每个实体。


查看完整回答
反对 回复 2022-07-22
  • 2 回答
  • 0 关注
  • 73 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信