Symfony 4 Guard Neo4j OGM

У меня возникли проблемы с тем, чтобы связка Neo4j OGM / Symfony работала с Symfony Guard. Я успешно добавил пользователей в базу данных. к сожалению, он не хочет входить в систему, и я получаю следующую ошибку:

Symfony\Component\Security\Core\Exception\AuthenticationServiceException: Class "App\Entity\Generic\User" is not a valid entity or mapped super class. in /home/vagrant/Code/support4neo/vendor/symfony/security/Core/Authentication/Provider/DaoAuthenticationProvider.php:85 Stack trace: 
#0 /home/vagrant/Code/support4neo/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php(142): session_start() 
#1 /home/vagrant/Code/support4neo/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php(299): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->start() 
#2 /home/vagrant/Code/support4neo/vendor/symfony/http-foundation/Session/Session.php(249): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->getBag('attributes') 
#3 /home/vagrant/Code/support4neo/vendor/symfony/http-foundation/Session/Session.php(271): Symfony\Component\HttpFoundation\Session\Session->getBag('attributes') 
#4 /home/vagrant/Code/support4neo/vendor/symfony/http-foundation/Session/Session.php(73): Symfony\Component\HttpFoundation\Session\Session->getAttributeBag() 
#5 /home/vagrant/Code/support4neo/vendor/symfony/security/Http/Firewall/ContextListener.php(88): Symfony\Component\HttpFoundation\Session\Session->get('_security_main') 
#6 /home/vagrant/Code/support4neo/vendor/symfony/security-bundle/Debug/WrappedListener.php(46): Symfony\Component\Security\Http\Firewall\ContextListener->handle(Object(Symfony\Component\HttpKernel\Event\GetResponseEvent)) 
#7 /home/vagrant/Code/support4neo/vendor/symfony/security-bundle/Debug/TraceableFirewallListener.php(35): Symfony\Bundle\SecurityBundle\Debug\WrappedListener->handle(Object(Symfony\Component\HttpKernel\Event\GetResponseEvent)) 
#8 /home/vagrant/Code/support4neo/vendor/symfony/security/Http/Firewall.php(56): Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener->handleRequest(Object(Symfony\Component\HttpKernel\Event\GetResponseEvent), Object(Symfony\Component\DependencyInjection\Argument\RewindableGenerator)) 
#9 /home/vagrant/Code/support4neo/vendor/symfony/security-bundle/EventListener/FirewallListener.php(48): Symfony\Component\Security\Http\Firewall->onKernelRequest(Object(Symfony\Component\HttpKernel\Event\GetResponseEvent)) 
#10 [internal function]: Symfony\Bundle\SecurityBundle\EventListener\FirewallListener->onKernelRequest(Object(Symfony\Component\HttpKernel\Event\GetResponseEvent), 'kernel.request', Object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher)) 
#11 /home/vagrant/Code/support4neo/vendor/symfony/event-dispatcher/Debug/WrappedListener.php(104): call_user_func(Array, Object(Symfony\Component\HttpKernel\Event\GetResponseEvent), 'kernel.request', Object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher)) 
#12 /home/vagrant/Code/support4neo/vendor/symfony/event-dispatcher/EventDispatcher.php(212): Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(Object(Symfony\Component\HttpKernel\Event\GetResponseEvent), 'kernel.request', Object(Symfony\Component\EventDispatcher\EventDispatcher)) 
#13 /home/vagrant/Code/support4neo/vendor/symfony/event-dispatcher/EventDispatcher.php(44): Symfony\Component\EventDispatcher\EventDispatcher->doDispatch(Array, 'kernel.request', Object(Symfony\Component\HttpKernel\Event\GetResponseEvent)) 
#14 /home/vagrant/Code/support4neo/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php(139): Symfony\Component\EventDispatcher\EventDispatcher->dispatch('kernel.request', Object(Symfony\Component\HttpKernel\Event\GetResponseEvent)) 
#15 /home/vagrant/Code/support4neo/vendor/symfony/http-kernel/HttpKernel.php(125): Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch('kernel.request', Object(Symfony\Component\HttpKernel\Event\GetResponseEvent)) 
#16 /home/vagrant/Code/support4neo/vendor/symfony/http-kernel/HttpKernel.php(66): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) 
#17 /home/vagrant/Code/support4neo/vendor/symfony/http-kernel/Kernel.php(190): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) 
#18 /home/vagrant/Code/support4neo/public/index.php(37): Symfony\Component\HttpKernel\Kernel->handle(Object(Symfony\Component\HttpFoundation\Request)) 
#19 {main}

Что я мог делать не так?

Заранее спасибо!

Класс пользователя:

<?php
/**
 * Created by PhpStorm.
 * User: kevin.oosterhout
 * Date: 24/04/2018
 * Time: 20:58
 */

namespace App\Entity\Generic;

use GraphAware\Neo4j\Client\Client;
use GraphAware\Neo4j\OGM\Annotations as OGM;
use Symfony\Component\Security\Core\User\UserInterface;


/**
 *
 * @OGM\Node(label = "User")
 */
class User implements UserInterface
{

    /**
     * @OGM\GraphId()
     */
    protected $id;
    /**
     * @OGM\Property(type = "string")
     */
    protected $firstname;
    /**
     * @OGM\Property(type = "string")
     */
    protected $lastname;
    /**
     * @OGM\Property(type = "string")
     */
    protected $email;
    /**
     * @OGM\Property(type = "string")
     */
    protected $password;

    /**
     * @return mixed
     */
    public function getFirstname()
    {
        return $this->firstname;
    }

    /**
     * @return mixed
     */
    public function getLastname()
    {
        return $this->lastname;
    }

    /**
     * @return mixed
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @return mixed
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * @param mixed $firstname
     */
    public function setFirstname($firstname): void
    {
        $this->firstname = $firstname;
    }

    /**
     * @param mixed $lastname
     */
    public function setLastname($lastname): void
    {
        $this->lastname = $lastname;
    }

    /**
     * @param mixed $email
     */
    public function setEmail($email): void
    {
        $this->email = $email;
    }

    /**
     * @param mixed $password
     */
    public function setPassword($password): void
    {
        $this->password = $password;
    }


    /**
     * Returns the roles granted to the user.
     *
     * <code>
     * public function getRoles()
     * {
     *     return array('ROLE_USER');
     * }
     * </code>
     *
     * Alternatively, the roles might be stored on a ``roles`` property,
     * and populated in any number of different ways when the user object
     * is created.
     *
     * @return (Role|string)[] The user roles
     */
    public function getRoles()
    {
        return array('ROLE_USER');
    }

    /**
     * Returns the salt that was originally used to encode the password.
     *
     * This can return null if the password was not encoded using a salt.
     *
     * @return string|null The salt
     */
    public function getSalt()
    {
        return null;
    }

    /**
     * Returns the username used to authenticate the user.
     *
     * @return string The username
     */
    public function getUsername()
    {
        return $this->email;
    }

    /**
     * Removes sensitive data from the user.
     *
     * This is important if, at any given point, sensitive information like
     * the plain-text password is stored on this object.
     */
    public function eraseCredentials()
    {
        // TODO: Implement eraseCredentials() method.
    }
}

Класс аутентификатора:

<?php
/**
 * Created by PhpStorm.
 * User: kevin.oosterhout
 * Date: 03/05/2018
 * Time: 17:37
 */

namespace App\Security;


use App\Entity\Generic\User;
use App\Forms\LoginForm;
use GraphAware\Neo4j\OGM\EntityManager;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;

class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{

    public function getCredentials(Request $request)
    {
        return array(
            'username' => $request->request->get('_username'),
            'password' => $request->request->get('_password'),
        );
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        if ($credentials['username'] === null){
            return null;
        }
        $user = $userProvider->loadUserByUsername($credentials['username']);

        return $user;

    }

    public function checkCredentials($credentials, UserInterface $user)
    {

        return true;
    }

    protected function getLoginUrl()
    {
        // TODO: Implement getLoginUrl() method.
    }

    public function supports(Request $request)
    {
        return false;
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        // TODO: Implement onAuthenticationSuccess() method.
    }
}

Безопасность.Ямл

security:
    encoders:
        App\Entity\Generic\User:
          algorithm: bcrypt

    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        UserProvider:
            id: 'App\Security\UserProvider'

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~
            form_login:
                login_path: login
                check_path: login
            guard:
                authenticators:
                    - 'App\Security\LoginFormAuthenticator'



            # activate different ways to authenticate

            # http_basic: true
            # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate

            # form_login: true
            # https://symfony.com/doc/current/security/form_login_setup.html

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        # - { path: ^/admin, roles: ROLE_ADMIN }
        # - { path: ^/profile, roles: ROLE_USER }

Провайдер пользователя:

<?php
/**
 * Created by PhpStorm.
 * User: kevin.oosterhout
 * Date: 04/05/2018
 * Time: 07:38
 */

namespace App\Security;


use App\Entity\Generic\User;
use GraphAware\Neo4j\OGM\EntityManager;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;

class UserProvider implements UserProviderInterface
{

    protected $userRepository;

    public function __construct(EntityManager $entityManager)
    {
        $this->userRepository = $entityManager->getRepository(User::class);
    }

    /**
     * @param string $username
     * @return null|User
     */
    public function loadUserByUsername($username)
    {

        return $this->userRepository->findOneBy(['email' => $username]);
    }

    public function refreshUser(UserInterface $user)
    {

        if (!$user instanceof User) {
            throw new UnsupportedUserException(
                sprintf('Instance of %s is not support', get_class($user))
            );
        }

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

    public function supportsClass($class)
    {
        return User::class === $class;
    }
}

Редактировать: В настоящее время он не регистрирует меня и не выдает ошибок. Я выполнил шаги, описанные @dbrumann и @Christophe Willemsen

Можете ли вы разместить репо на github со своим кодом для аутентификатора защиты, чтобы мы могли протестировать?

Christophe Willemsen 07.05.2018 08:55

Я загрузил это: github.com/djkevino/Support4Neo

djkevino 07.05.2018 10:38
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
0
2
331
2

Ответы 2

Думаю, проблема в вашем security.yaml:

providers:
    UserProvider:
        entity:
            class: 'App\Entity\Generic\User'
            property: email

Этот провайдер пытается использовать Doctrine ORM для загрузки пользователей из. Поскольку ваш пользовательский объект не является Doctrine-Entity, то есть в нем отсутствуют аннотации доктрины, он не работает. Несмотря на то, что пакет регистрирует менеджеров сущностей, кажется, что они не используются поставщиком пользователей.

Вы можете создать пользовательский провайдер, вдохновленный EntityUserProvider.

Я не уверен, придерживаются ли менеджеры сущностей ogm интерфейсов доктрины, но если они это сделают, вы можете настроить провайдера пользователя доктрины по умолчанию для использования диспетчера сущностей neo4j, настроив конфигурацию службы, но это настоящая боль, потому что у вас есть чтобы перезаписать службу UserProvider, а затем ввести новый ManagerRegistry с вашим менеджером сущностей в нем. Итак, создание собственного UserProvider действительно кажется предпочтительным способом.

Спасибо, это помогло мне продвинуться дальше, к сожалению, это все еще не входит в меня. Но я тоже не получаю сообщения об ошибке.

djkevino 07.05.2018 06:43

Посмотрите на веб-профилировщик на вкладке безопасности. Может быть, это даст вам некоторую информацию. Также мы надеемся, что dev.log даст вам ключ к разгадке. Например, я часто делаю ошибку, когда забываю назначить пользователю хотя бы одну группу, например ROLE_USER.

dbrumann 07.05.2018 07:51

Ответ от @dbrumman правильный, вам понадобится собственный UserProvider.

У меня есть демонстрационный пример на Github, проверьте здесь: https://github.com/ikwattro/neo4j-ogm-symfony-security

Также существует PullRequest, который показывает, как добавлять роли на основе содержимого Neo4j:

https://github.com/ikwattro/neo4j-ogm-symfony-security/pull/1/files

Другие вопросы по теме