Php Symfony:根据LDAP服务器对用户进行身份验证,但仅当其用户名位于自定义数据库表中时才允许登录

Php Symfony:根据LDAP服务器对用户进行身份验证,但仅当其用户名位于自定义数据库表中时才允许登录,php,symfony,authentication,ldap,Php,Symfony,Authentication,Ldap,首先简要说明我的任务。我使用的是symfony2.8,有一个带有restapi和SonataAdminBundle的应用程序。网站访问者可以通过REST API发布某些数据,该API将持久化到数据库中。某一组员工应通过管理区管理这些数据 对管理区域的访问应使用用户名和密码进行保护。有一个实体Employee具有属性username,但没有密码。应针对LDAP服务器进行身份验证,但对管理区域的访问应仅限于实体Employee中存在的员工,即引用数据库表 对于LDAP身份验证,我使用Symfony

首先简要说明我的任务。我使用的是symfony2.8,有一个带有restapi和SonataAdminBundle的应用程序。网站访问者可以通过REST API发布某些数据,该API将持久化到数据库中。某一组员工应通过管理区管理这些数据

对管理区域的访问应使用用户名和密码进行保护。有一个实体
Employee
具有属性
username
,但没有密码。应针对LDAP服务器进行身份验证,但对管理区域的访问应仅限于实体
Employee
中存在的员工,即引用数据库表

对于LDAP身份验证,我使用Symfony 2.8中的新LDAP组件

除此之外,内存中应该有一个名为
的管理员帐户

这就是我现在拥有的:

app/config/services.yml

app/config/security.yml

src/AppBundle/Entity/Employee.php
src/AppBundle/Security/DbUserProvider.php

然后,甚至不会调用方法
loadUserByUsername
,所有用户都可以登录,包括数据库中的用户和非数据库中的用户

内存中的
用户管理员在任何情况下都可以毫无问题地登录

谢谢你的帮助。如果有人认为我的整个方法不好,并且知道更好的方法,请不要吝惜批评


我知道有FOSUserBundle和SonataUserBundle,但我更喜欢自定义用户提供者,因为我不想让实体员工膨胀,因为我真的不需要所有这些属性,如密码、salt、isLocked等。此外,我不认为在我的特定情况下配置SonataUserBundle会简单得多。如果您仍然认为有更优雅的方式来完成这两个捆绑包的任务,我将非常感谢您的建议。

您可以为每个防火墙配置用户检查器,您的db用户提供程序实际上不是用户提供程序,因为它不具备验证用户身份所需的所有信息(例如密码) 因此,我要做的是,我将删除db用户提供程序并添加一个用户检查器,而用户检查器的主要思想是在身份验证过程中添加额外的检查,在您的情况下,我们需要检查用户是否在employee表中

要实现这一点,您需要做三件事

实现UserCheckerInterface
Symfony\Component\Security\Core\User\UserCheckerInterface

检查用户是否在employee表中,是否在
checkPostAuth()方法中

将新用户检查器作为服务公开

services:
    app.employee_user_checker:
        class: Path\To\Class\EmployeeUserChecker
更改防火墙配置以使用新的用户检查器

security:
    firewalls:
        admin:
            pattern: ^/admin
            user_checker: app.employee_user_checker
            #...

回答得很好!它很好地解释了正确的方法,并指出了我的方法的缺陷。还有一些小问题我必须解决,但现在我知道如何干扰登录检查过程。非常感谢你!
namespace AppBundle\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Doctrine\ORM\Mapping as ORM;

class Employee implements UserInterface, EquatableInterface
{
    // other properties

    private $username;

    // getters and setters for the other properties

    public function getUsername()
    {
        return $this->username;
    }

    public function getRoles()
    {
        return array('ROLE_USER');
    }

    public function getPassword()
    {
        return null;
    }

    public function getSalt()
    {
        return null;
    }

    public function eraseCredentials()
    {
    }

    public function isEqualTo(UserInterface $user)
    {
        if (!$user instanceof Employee) {
            return false;
        }

        if ($this->username !== $user->getUsername()) {
            return false;
        }

        return true;
    }
}
<?php

namespace AppBundle\Security;

use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Doctrine\ORM\EntityManager;
use AppBundle\Entity\Employee;

class DbUserProvider implements UserProviderInterface
{
    private $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function loadUserByUsername($username)
    {
        $repository = $this->em->getRepository('AppBundle:Employee');
        $user = $repository->findOneByUsername($username);

        if ($user) {
            return new Employee();
        }

        throw new UsernameNotFoundException(
            sprintf('Username "%s" does not exist.', $username)
        );
    }

    public function refreshUser(UserInterface $user)
    {
        if (!$user instanceof Employee) {
            throw new UnsupportedUserException(
                sprintf('Instances of "%s" are not supported.', get_class($user))
            );
        }

        return $this->loadUserByUsername($user->getUsername());
    }

    public function supportsClass($class)
    {
        return $class === 'AppBundle\Entity\Employee';
    }
}
chain_provider:
    chain:
        providers: [app_users, db_user]
services:
    app.employee_user_checker:
        class: Path\To\Class\EmployeeUserChecker
security:
    firewalls:
        admin:
            pattern: ^/admin
            user_checker: app.employee_user_checker
            #...