具有外部用户源的OAuth2服务器


OAuth2 server with an external user source

我正在用伟大的FOSOAuthServerBundle构建一个OAuth2服务器。

我的Symfony应用程序验证来自另一个来源(实际上是另一个服务器(的用户。

我已经创建了一个自定义的UserProvider,它可以很好地与默认的Symfony安全层配合使用。我有UserInterface的实现,但它显然不是数据库的实体。

实现AccessTokenRefreshToken&AuthCode,如条令安装说明中所述,我将用户参考定义为

//...
/**
 * @ORM'Column(type="integer")
 */
protected $user_id;
//...

在那之前,它看起来合乎逻辑吗?

现在真正的问题是:我在哪里指定将用户链接到不同令牌的方式


我也一直在问关于官方回购的问题,以提高可见性

我最终做了两件事:

  • 重写令牌setter&属性user的getter
  • 使用条令LifecycleEvent监听器

首先扩展令牌类(例如使用Trait(

namespace AppBundle'Entity;
use AppBundle'Security'User;
use Symfony'Component'Security'Core'User'UserInterface;
trait AppTokenTrait
{
    /**
     * @ORM'Column(type="string")
     * @var string
     */
    protected $username;
    public function setUser(UserInterface $user)
    {
        if (!$user instanceof User) {
            throw new 'InvalidArgumentException(
                sprintf("User must be an instance of %s", User::class)
            );
        }
        $this->username = $user->getUsername();
        $this->user = $user;
    }
    public function getUser()
    {
        if (!$this->user) {
            throw new 'RuntimeException(
                "Unable to get user - user was not loaded by postLoad"
            );
        }
        return $this->user;
    }
    /**
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }
}

在3个令牌类中(不要忘记更新数据库模式(:

//...
    use AppTokenTrait;
//...

创建侦听器

namespace AppBundle'Services;
use AppBundle'Entity'AccessToken;
use AppBundle'Entity'AuthCode;
use AppBundle'Entity'RefreshToken;
use AppBundle'Security'UserProvider;
use Doctrine'ORM'Event'LifecycleEventArgs;
class AppTokenListener
{
    /**
     * @var UserProvider
     */
    protected $userProvider;
    public function __construct(UserProvider $userProvider)
    {
        $this->userProvider = $userProvider;
    }
    public function postLoad(LifecycleEventArgs $event)
    {
        $object = $event->getObject();
        if (
            $object instanceof AccessToken or
            $object instanceof AuthCode or
            $object instanceof RefreshToken
        ) {
            $user = $this->userProvider->loadUserByUsername($object->getUsername());
            $object->setUser($user);
        }
    }
}

将其注册为服务

app.token.listener:
    class: AppBundle'Services'AppTokenListener
    tags:
        - { name: doctrine.event_listener, event: postLoad }

用户对象现在应该始终附加到令牌