Проблема в каждом втором запросе?

Коллеги, здравствуйте!

Возникла проблема в системе безопасности synfony (firewalls)

Посмотрите на гифку.
5dcc3df040dc6751050984.gif

По поводу анимации, при запросе я ожидаю ошибку и только её!


An exception occurred while executing 'INSERT INTO services (name, altName, lft, lvl, rgt, root_id, parent_id) VALUES (?, ?, ?, ?, ?, ?, ?)' with params [\"A\", null, 0, 0, 0, null, 26]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'A-26' for key 'services_unique_name_parent_id'


Описание проблемы.
Когда я выполняю запрос, в первый раз все срабатывает, стоит мне тут же выполнить повторный запрос, тут же возникает ошибка There is no user provider for user \"App\\Entity\\User\".

И так далее, получается что через раз происходит ошибка.

Вот некоторые параметры.

config/admin/packages/security.yaml
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        in_memory: { memory: null }

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        get_access_token:
            pattern: ^/security.getAccessToken
            guard:
                entry_point: App\Security\CreateAccessToken

        check_access_token:
            pattern: ^/security.checkAccessToken
            guard:
                entry_point: App\Security\CheckAccessToken

        main:
            anonymous: ~
            guard:
                authenticators :
                    - App\Security\TokenAuthenticator


src/Security/TokenAuthenticator.php
TokenAuthenticator

<?php

namespace App\Security;

use App\Entity\User;
use App\Exception\Api\EAuthorisationError;
use App\Exception\Api\ExceptionInvalidRequest;
use Doctrine\ORM\EntityManagerInterface;
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\AlgorithmManagerFactory;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
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\AbstractGuardAuthenticator;

/**
 * Class TokenAuthenticator 
 * @package App\Security
 */
class TokenAuthenticator extends AbstractGuardAuthenticator
{

    /** @var AlgorithmManagerFactory */
    private $algorithmManagerFactory;

    /** @var AlgorithmManager */
    private $algorithmManager;

    /** @var EntityManagerInterface */
    private $entityManager;
    /** @var string */
    private $ip;


    /**
     * AppAuthAuthenticator constructor.
     * @param EntityManagerInterface $entityManager
     * @param AlgorithmManagerFactory $algorithmManagerFactory
     */
    public function __construct(EntityManagerInterface $entityManager, AlgorithmManagerFactory $algorithmManagerFactory)
    {
        $this->entityManager = $entityManager;
        $this->algorithmManagerFactory = $algorithmManagerFactory;
        $this->algorithmManager = $this->algorithmManagerFactory->create(["RS256", "HS512"]);
        $this->ip = $_SERVER['REMOTE_ADDR'];
    }

    /**
     * @param string $token
     * @return bool
     * @throws EAuthorisationError
     */
    public function verification(string $token): bool
    {
        $jwk = new JWK([
            "kty" => "oct",
            "k" => base64_encode($_ENV["JWT_KEY"] . $this->ip),
        ]);

        // The serializer manager. We only use the JWS Compact Serialization Mode.
        $serializerManager = new JWSSerializerManager([
            new CompactSerializer(),
        ]);

        $jwsVerifier = new JWSVerifier($this->algorithmManager);

        try {
            $jws = $serializerManager->unserialize($token);
        }catch (\Exception $exception) {
            throw new EAuthorisationError("Не удалось проверить токен");
        }

        return $jwsVerifier->verifyWithKey($jws, $jwk, 0);
    }

    /**
     * @param Request $request
     * @return bool|void
     */
    public function supports(Request $request)
    {
        return true;
    }


    /**
     * @param Request $request
     * @return array
     * @throws EAuthorisationError
     */
    public function getCredentials(Request $request)
    {
        try {
            preg_match('/Bearer\s+(.*?)$/m', $request->headers->get("authorization"), $match);
            return [
                "token" => $match[1],
            ];
        }catch (\Exception $exception) {
            throw new EAuthorisationError("Не верный токен");
        }
    }



    /**
     * Return a UserInterface object based on the credentials.
     *
     * The *credentials* are the return value from getCredentials()
     *
     * You may throw an AuthenticationException if you wish. If you return
     * null, then a UsernameNotFoundException is thrown for you.
     *
     * @param mixed $credentials
     *
     * @param UserProviderInterface $userProvider
     * @return User|UserProviderInterface
     */
    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        return new User();
    }

    /**
     * Returns true if the credentials are valid.
     *
     * If any value other than true is returned, authentication will
     * fail. You may also throw an AuthenticationException if you wish
     * to cause authentication to fail.
     *
     * The *credentials* are the return value from getCredentials()
     *
     * @param mixed $credentials
     *
     * @return bool
     *
     * @throws AuthenticationException
     * @throws EAuthorisationError
     */
    public function checkCredentials($credentials, UserInterface $user)
    {
        if ($this->verification($credentials["token"])) {
            return true;
        }

        throw new EAuthorisationError("Не верный токен");
    }

    /**
     * Called when authentication executed, but failed (e.g. wrong username password).
     *
     * This should return the Response sent back to the user, like a
     * RedirectResponse to the login page or a 403 response.
     *
     * If you return null, the request will continue, but the user will
     * not be authenticated. This is probably not what you want to do.
     *
     * @return Response|null
     */
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        return null;
    }

    /**
     * Called when authentication executed and was successful!
     *
     * This should return the Response sent back to the user, like a
     * RedirectResponse to the last page they visited.
     *
     * If you return null, the current request will continue, and the user
     * will be authenticated. This makes sense, for example, with an API.
     *
     * @param string $providerKey The provider (i.e. firewall) key
     *
     * @return Response|null
     */
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        return null;
    }

    /**
     * Does this method support remember me cookies?
     *
     * Remember me cookie will be set if *all* of the following are met:
     *  A) This method returns true
     *  B) The remember_me key under your firewall is configured
     *  C) The "remember me" functionality is activated. This is usually
     *      done by having a _remember_me checkbox in your form, but
     *      can be configured by the "always_remember_me" and "remember_me_parameter"
     *      parameters under the "remember_me" firewall key
     *  D) The onAuthenticationSuccess method returns a Response object
     *
     * @return bool
     */
    public function supportsRememberMe()
    {
        // TODO: Implement supportsRememberMe() method.
    }

    /**
     * Returns a response that directs the user to authenticate.
     *
     * This is called when an anonymous request accesses a resource that
     * requires authentication. The job of this method is to return some
     * response that "helps" the user start into the authentication process.
     *
     * Examples:
     *
     * - For a form login, you might redirect to the login page
     *
     *     return new RedirectResponse('/login');
     *
     * - For an API token authentication system, you return a 401 response
     *
     *     return new Response('Auth header required', 401);
     *
     * @param Request $request The request that resulted in an AuthenticationException
     * @param AuthenticationException $authException The exception that started the authentication process
     *
     * @return Response
     * @throws EAuthorisationError
     * @throws ExceptionInvalidRequest
     */
    public function start(Request $request, AuthenticationException $authException = null)
    {
        if (!$this->supports($request)) {
            throw new ExceptionInvalidRequest("Требуется параметр [token]!", $request);
        }

        $credentials = $this->getCredentials($request);

        if ($this->verification($credentials["token"])) {
            return new Response("");
        }

        throw new EAuthorisationError("Token is not valid!");
    }
}

  • Вопрос задан
  • 133 просмотра
Решения вопроса 1
BoShurik
@BoShurik Куратор тега Symfony
Symfony developer
Вам нужно либо реализовать примитивный провайдер, который будет возвращать new User() вместо вашего кода
public function getUser($credentials, UserProviderInterface $userProvider)
{
    return new User();
}

либо добавить stateless: true
Проблема в ContextListener который
ContextListener manages the SecurityContext persistence through a session.

Он ожидает, что в сессии находится токен пользователя и пытается его восстановить из провайдера, которого у вас нет.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
WEBINAR Москва
от 190 000 руб.
Homeapp Москва
от 180 000 руб.
АКМЭ сервис Санкт-Петербург
от 100 000 руб.
11 дек. 2019, в 05:36
5000 руб./за проект
11 дек. 2019, в 01:58
2500 руб./за проект
11 дек. 2019, в 01:57
1000 руб./в час