Symfony FOS OAuth с пользовательским пользователем

Как можно реализовать сервер OAuth на основе FOSOAuthServerBundle без использования FOSUserBundle?

Мой пользовательский класс начинается как его:

<?php

namespace AppBundle\Entity;

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

/**
*
* @ORM\Entity
* @ORM\Table(name="user")
* @ORM\Entity(repositoryClass="AppBundle\Entity\UserRepository")
*/
class User implements UserInterface

Мой класс пользовательского репозитория начинается с этого:

<?php

namespace AppBundle\Entity;

use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NoResultException;

class UserRepository extends EntityRepository implements UserLoaderInterface, UserProviderInterface

В моем security.yml я включил следующее:

    providers:
        user_db:
            entity:
                class: AppBundle\Entity\User
                property: username

И, наконец, config.yml:

fos_oauth_server:
    db_driver: orm
    client_class: AppBundle\Entity\OAuthClient
    access_token_class: AppBundle\Entity\OAuthAccessToken
    refresh_token_class: AppBundle\Entity\OAuthRefreshToken
    auth_code_class: AppBundle\Entity\OAuthAuthCode
    service:
        options:
            access_token_lifetime: 3600

        user_provider: user_db
        #user_provider: AppBundle\Entity\UserRepository
        #user_provider: AppBundle\Entity\User

Сейчас выдает исключение:

[1] Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function loadUserByUsername() on null
    at n/a
        in /home/wanderson/api/vendor/friendsofsymfony/oauth-server-bundle/Storage/OAuthStorage.php line 161

    at FOS\OAuthServerBundle\Storage\OAuthStorage->checkUserCredentials(object(OAuthClient), 'admin', 'admin')
        in /home/wanderson/api/vendor/friendsofsymfony/oauth2-php/lib/OAuth2.php line 929

    at OAuth2\OAuth2->grantAccessTokenUserCredentials(object(OAuthClient), array('grant_type' => 'password', 'scope' => null, 'code' => null, 'redirect_uri' => null, 'username' => 'admin', 'password' => 'admin', 'refresh_token' => null))
        in /home/wanderson/api/vendor/friendsofsymfony/oauth2-php/lib/OAuth2.php line 815

    at OAuth2\OAuth2->grantAccessToken(object(Request))
        in /home/wanderson/api/vendor/friendsofsymfony/oauth-server-bundle/Controller/TokenController.php line 42

    at FOS\OAuthServerBundle\Controller\TokenController->tokenAction(object(Request))
        in  line 

    at call_user_func_array(array(object(TokenController), 'tokenAction'), array(object(Request)))
        in /home/wanderson/api/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php line 153

    at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), '1')
        in /home/wanderson/api/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php line 68

    at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), '1', true)
        in /home/wanderson/api/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php line 169

    at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
        in /home/wanderson/api/web/app_dev.php line 30

    at require('/home/wanderson/api/web/app_dev.php')
        in /home/wanderson/api/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php line 40

person Wanderson Silva    schedule 02.11.2016    source источник


Ответы (1)


Создайте провайдера пользователя или, если вы хотите использовать свой класс репозитория, прочитайте «как определить репозиторий как сервис» (я не знаю, работает ли он в новейшей версии или нет):

https://stackoverflow.com/a/17230333/6848076 https://stackoverflow.com/а/31807608/6848076

Но я не рекомендовал этот путь

<?php 

namespace AppBundle\Security\Provider\UserProvider;

use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\ORM\NoResultException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Serializer\Exception\UnsupportedException;
use Doctrine\ORM\EntityManager;

class UserProvider implements UserProviderInterface
{
    protected $class;

    protected $userRepository;

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

    public function loadUserByUsername($username)
    {
        $user = $this->userRepository->findOneBy(array('username' => $username));
        if (null === $user) {
            $message = sprintf(
                'Unable to find an active User object identified by "%s"',
                $username
            );
            throw new UsernameNotFoundException($message, 0, $failed);
        }
        return $user;
    }

    public function refreshUser(UserInterface $user)
    {
        $class = get_class($user);
        if (false == $this->supportsClass($class)) {
            throw new UnsupportedException(
                sprintf(
                    'Instances of "%s" are not supported',
                    $class
                )
            );
        }
        return $this->userRepository->find($user->getId());
    }

    public function supportsClass($class)
    {
        return $this->class === $class
            || is_subclass_of($class, $this->class);

    }
}

О сервисах вы можете прочитать: http://symfony.com/doc/current/service_container.html Определите службу поставщика в {каталог_проекта}/src/AppBundle/Resources/config/service.yml

parameters:
    user.class: AppBundle\Entity\User
    user.provider.class: AppBundle\Security\Provider\UserProvider
services:
    user.provider:
      class: %user.provider.class%
      arguments: [@doctrine.orm.entity_manager, %user.class%]

Измените конфигурацию fosoauth в config.yml:

fos_oauth_server:
    db_driver: orm
    client_class: AppBundle\Entity\OAuthClient
    access_token_class: AppBundle\Entity\OAuthAccessToken
    refresh_token_class: AppBundle\Entity\OAuthRefreshToken
    auth_code_class: AppBundle\Entity\OAuthAuthCode
    service:
        options:
            access_token_lifetime: 3600
        user_provider: user.provider

О security.yml вы можете прочитать: http://symfony.com/doc/current/security.html

person Hardy Rust    schedule 02.11.2016
comment
Извините, я новичок в Symfony, я не уверен, где разместить эту конфигурацию службы провайдера. Я попытался поместить его в security.providers (security.yml) точно так же, как в вашем примере, и я получил Symfony, чтобы сказать мне, что этот файл не содержит действительного YAML. PS: класс UserProvider, за исключением конструктора, практически идентичен моему классу UserRepository. - person Wanderson Silva; 02.11.2016