Php Symfony-投票者在/GET列表上返回空对象

Php Symfony-投票者在/GET列表上返回空对象,php,symfony,jwt,api-platform.com,symfony4-voter,Php,Symfony,Jwt,Api Platform.com,Symfony4 Voter,我正在使用应用程序上实现的Symfony5和apiplate 我有一个经典的/GET路由,它通过上下文生成器向未经身份验证的用户的某些属性添加动态组“匿名:读取”,从而只返回所有用户实体的少数字段 由于用户不需要拥有JWT令牌,我已将其添加到我的security.yml文件的access\u control部分: access_control: - { path: ^/users, roles: IS_AUTHENTICATED_ANONYMOUSLY } 此路由也被具有不同授权的其他类型

我正在使用应用程序上实现的
Symfony5
apiplate

我有一个经典的
/GET
路由,它通过
上下文生成器向未经身份验证的用户的某些属性添加动态组
“匿名:读取”
,从而只返回所有
用户
实体的少数字段

由于用户不需要拥有
JWT令牌
,我已将其添加到我的
security.yml
文件的
access\u control
部分:

access_control:
  - { path: ^/users, roles: IS_AUTHENTICATED_ANONYMOUSLY }
此路由也被具有不同授权的其他类型的用户使用,因此它通过一个
投票者

投票者
是我阻止的地方,我应该在
$subject
变量中接收的对象列表最终为空,从投票者的
支持
函数返回false,从而拒绝访问

如果我从
/GET
路径注释中撤销
安全性
约束,我确实会收到我想要的
用户列表,其中只包含所需的字段

我无法理解为什么此对象列表的
$subject
为空

User.php:

/**
 * @ApiResource(
 *     attributes={
 *          "normalization_context"={"groups"={"user:read", "user:list"}},
 *          "denormalization_context"={"groups"={"user:write"}},
 *          "order"={"availabilities.start": "ASC"}
 *     },
 *     collectionOperations={
 *          "get"={
 *              "mehtod"="GET",
 *              "security"="is_granted('LIST', object)",
 *              "normalization_context"={"groups"={"user:list"}},
 *          },
 *          "post"={
 *              "method"="POST",
 *              "security_post_denormalize"="is_granted('POST', object)",
 *              "denormalization_context"={"groups"={"user:write"}}
 *          }
 *     },
 *     itemOperations={
 *          "get"={
 *              "method"="GET",
 *              "security"="is_granted('ROLE_USER')"
 *          },
 *          "put"={
 *              "method"="PUT",
 *              "security"="is_granted('PUT', object)"
 *          },
 *          "delete"={
 *              "method"="DELETE",
 *              "security"="is_granted('ROLE_ADMIN')"
 *          }
 *     }
 * )
 * @ORM\Entity(repositoryClass=UserRepository::class)
 */
class User
{

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups({"user:read", "user:list"})
     */
    private $id;

    /**
     * @ORM\Column(type="boolean")
     * @Groups({"user:read", "user:list", "user:write", "anonym:read"})
     */
    private $active;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     * @Groups({"user:read", "user:list", "user:write", "anonym:read"})
     */
    private $photo;

    /**
     * @ORM\Column(type="text")
     * @Groups({"user:read", "user:list", "user:write"})
     */
    private $description;

}

final class UserContextBuilder implements SerializerContextBuilderInterface
{
    private $decorated;
    private $authorizationChecker;

    public function __construct(SerializerContextBuilderInterface $decorated, AuthorizationCheckerInterface $authorizationChecker)
    {
        $this->decorated = $decorated;
        $this->authorizationChecker = $authorizationChecker;
    }

    public function createFromRequest(Request $request, bool $normalization, ?array $extractedAttributes = null): array
    {
        $context = $this->decorated->createFromRequest($request, $normalization, $extractedAttributes);
        $resourceClass = $context['resource_class'] ?? null;

        if (
            $resourceClass === User::class && isset($context['groups']) &&
            !$this->authorizationChecker->isGranted('ROLE_USER') &&
            true == $normalization
        ) {
            $context['groups'][] = 'anonym:read';
        }

        return $context;
    }
}


class UserVoter extends AbstractVoter
{
    protected function supports($attribute, $subject)
    {
        return parent::supports($attribute, $subject) &&
            ($subject instanceof User ||
                $this->arrayOf($subject, User::class));
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        /** @var User $user */
        $user = $token->getUser();

        if ($this->accessDecisionManager->decide($token, [GenericRoles::ROLE_ADMIN])) {
            return true;
        }

        switch ($attribute) {
            case Actions::LIST:
                return $user->hasRole(GenericRoles::ROLE_USER) || !$user instanceof User;
            case Actions::PUT:
                return ($user->getId() == $subject->getUser()->getId() ||
                        $user->hasRole(GenericRoles::SOME_SPECIAL_ROLE));
            case Actions::POST:
                return $user->hasRole(GenericRoles::SOME_SPECIAL_ROLE);
        }

        return false;
    }
}

UserContextBuilder.php:

/**
 * @ApiResource(
 *     attributes={
 *          "normalization_context"={"groups"={"user:read", "user:list"}},
 *          "denormalization_context"={"groups"={"user:write"}},
 *          "order"={"availabilities.start": "ASC"}
 *     },
 *     collectionOperations={
 *          "get"={
 *              "mehtod"="GET",
 *              "security"="is_granted('LIST', object)",
 *              "normalization_context"={"groups"={"user:list"}},
 *          },
 *          "post"={
 *              "method"="POST",
 *              "security_post_denormalize"="is_granted('POST', object)",
 *              "denormalization_context"={"groups"={"user:write"}}
 *          }
 *     },
 *     itemOperations={
 *          "get"={
 *              "method"="GET",
 *              "security"="is_granted('ROLE_USER')"
 *          },
 *          "put"={
 *              "method"="PUT",
 *              "security"="is_granted('PUT', object)"
 *          },
 *          "delete"={
 *              "method"="DELETE",
 *              "security"="is_granted('ROLE_ADMIN')"
 *          }
 *     }
 * )
 * @ORM\Entity(repositoryClass=UserRepository::class)
 */
class User
{

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups({"user:read", "user:list"})
     */
    private $id;

    /**
     * @ORM\Column(type="boolean")
     * @Groups({"user:read", "user:list", "user:write", "anonym:read"})
     */
    private $active;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     * @Groups({"user:read", "user:list", "user:write", "anonym:read"})
     */
    private $photo;

    /**
     * @ORM\Column(type="text")
     * @Groups({"user:read", "user:list", "user:write"})
     */
    private $description;

}

final class UserContextBuilder implements SerializerContextBuilderInterface
{
    private $decorated;
    private $authorizationChecker;

    public function __construct(SerializerContextBuilderInterface $decorated, AuthorizationCheckerInterface $authorizationChecker)
    {
        $this->decorated = $decorated;
        $this->authorizationChecker = $authorizationChecker;
    }

    public function createFromRequest(Request $request, bool $normalization, ?array $extractedAttributes = null): array
    {
        $context = $this->decorated->createFromRequest($request, $normalization, $extractedAttributes);
        $resourceClass = $context['resource_class'] ?? null;

        if (
            $resourceClass === User::class && isset($context['groups']) &&
            !$this->authorizationChecker->isGranted('ROLE_USER') &&
            true == $normalization
        ) {
            $context['groups'][] = 'anonym:read';
        }

        return $context;
    }
}


class UserVoter extends AbstractVoter
{
    protected function supports($attribute, $subject)
    {
        return parent::supports($attribute, $subject) &&
            ($subject instanceof User ||
                $this->arrayOf($subject, User::class));
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        /** @var User $user */
        $user = $token->getUser();

        if ($this->accessDecisionManager->decide($token, [GenericRoles::ROLE_ADMIN])) {
            return true;
        }

        switch ($attribute) {
            case Actions::LIST:
                return $user->hasRole(GenericRoles::ROLE_USER) || !$user instanceof User;
            case Actions::PUT:
                return ($user->getId() == $subject->getUser()->getId() ||
                        $user->hasRole(GenericRoles::SOME_SPECIAL_ROLE));
            case Actions::POST:
                return $user->hasRole(GenericRoles::SOME_SPECIAL_ROLE);
        }

        return false;
    }
}

UserVoter.php:

/**
 * @ApiResource(
 *     attributes={
 *          "normalization_context"={"groups"={"user:read", "user:list"}},
 *          "denormalization_context"={"groups"={"user:write"}},
 *          "order"={"availabilities.start": "ASC"}
 *     },
 *     collectionOperations={
 *          "get"={
 *              "mehtod"="GET",
 *              "security"="is_granted('LIST', object)",
 *              "normalization_context"={"groups"={"user:list"}},
 *          },
 *          "post"={
 *              "method"="POST",
 *              "security_post_denormalize"="is_granted('POST', object)",
 *              "denormalization_context"={"groups"={"user:write"}}
 *          }
 *     },
 *     itemOperations={
 *          "get"={
 *              "method"="GET",
 *              "security"="is_granted('ROLE_USER')"
 *          },
 *          "put"={
 *              "method"="PUT",
 *              "security"="is_granted('PUT', object)"
 *          },
 *          "delete"={
 *              "method"="DELETE",
 *              "security"="is_granted('ROLE_ADMIN')"
 *          }
 *     }
 * )
 * @ORM\Entity(repositoryClass=UserRepository::class)
 */
class User
{

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups({"user:read", "user:list"})
     */
    private $id;

    /**
     * @ORM\Column(type="boolean")
     * @Groups({"user:read", "user:list", "user:write", "anonym:read"})
     */
    private $active;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     * @Groups({"user:read", "user:list", "user:write", "anonym:read"})
     */
    private $photo;

    /**
     * @ORM\Column(type="text")
     * @Groups({"user:read", "user:list", "user:write"})
     */
    private $description;

}

final class UserContextBuilder implements SerializerContextBuilderInterface
{
    private $decorated;
    private $authorizationChecker;

    public function __construct(SerializerContextBuilderInterface $decorated, AuthorizationCheckerInterface $authorizationChecker)
    {
        $this->decorated = $decorated;
        $this->authorizationChecker = $authorizationChecker;
    }

    public function createFromRequest(Request $request, bool $normalization, ?array $extractedAttributes = null): array
    {
        $context = $this->decorated->createFromRequest($request, $normalization, $extractedAttributes);
        $resourceClass = $context['resource_class'] ?? null;

        if (
            $resourceClass === User::class && isset($context['groups']) &&
            !$this->authorizationChecker->isGranted('ROLE_USER') &&
            true == $normalization
        ) {
            $context['groups'][] = 'anonym:read';
        }

        return $context;
    }
}


class UserVoter extends AbstractVoter
{
    protected function supports($attribute, $subject)
    {
        return parent::supports($attribute, $subject) &&
            ($subject instanceof User ||
                $this->arrayOf($subject, User::class));
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        /** @var User $user */
        $user = $token->getUser();

        if ($this->accessDecisionManager->decide($token, [GenericRoles::ROLE_ADMIN])) {
            return true;
        }

        switch ($attribute) {
            case Actions::LIST:
                return $user->hasRole(GenericRoles::ROLE_USER) || !$user instanceof User;
            case Actions::PUT:
                return ($user->getId() == $subject->getUser()->getId() ||
                        $user->hasRole(GenericRoles::SOME_SPECIAL_ROLE));
            case Actions::POST:
                return $user->hasRole(GenericRoles::SOME_SPECIAL_ROLE);
        }

        return false;
    }
}

如果有人知道为什么会这样,我会非常感激