From 040e86ea6d6398cd32450db93b0b01c1340bb36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Thu, 17 Aug 2023 00:36:25 +0200 Subject: [PATCH] Added API endpoint to get info about the API token currently used to authenticate the user --- src/Entity/UserSystem/ApiToken.php | 21 +++++++++++ src/State/CurrentApiTokenProvider.php | 51 +++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/State/CurrentApiTokenProvider.php diff --git a/src/Entity/UserSystem/ApiToken.php b/src/Entity/UserSystem/ApiToken.php index 0002fbaf..03b87a7a 100644 --- a/src/Entity/UserSystem/ApiToken.php +++ b/src/Entity/UserSystem/ApiToken.php @@ -23,18 +23,34 @@ declare(strict_types=1); namespace App\Entity\UserSystem; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Serializer\Filter\PropertyFilter; use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Base\TimestampTrait; use App\Repository\UserSystem\ApiTokenRepository; +use App\State\CurrentApiTokenProvider; +use App\State\PartDBInfoProvider; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints\NotBlank; #[ORM\Entity(repositoryClass: ApiTokenRepository::class)] #[ORM\Table(name: 'api_tokens')] #[ORM\HasLifecycleCallbacks] #[UniqueEntity(fields: ['name', 'user'])] + +#[ApiResource( + uriTemplate: '/current.{_format}', + description: 'A token used to authenticate API requests.', + operations: [new Get(openapiContext: ['summary' => 'Get information about the API token that is currently used.'])], + normalizationContext: ['groups' => ['token:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + provider: CurrentApiTokenProvider::class, +)] +#[ApiFilter(PropertyFilter::class)] class ApiToken { @@ -47,21 +63,26 @@ class ApiToken #[ORM\Column(type: Types::STRING)] #[NotBlank] + #[Groups('token:read')] protected string $name = ''; #[ORM\ManyToOne(inversedBy: 'api_tokens')] + #[Groups('token:read')] private ?User $user = null; #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)] + #[Groups('token:read')] private ?\DateTimeInterface $valid_until = null; #[ORM\Column(length: 68, unique: true)] private string $token; #[ORM\Column(type: Types::SMALLINT, enumType: ApiTokenLevel::class)] + #[Groups('token:read')] private ApiTokenLevel $level = ApiTokenLevel::READ_ONLY; #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)] + #[Groups('token:read')] private ?\DateTimeInterface $last_time_used = null; public function __construct(ApiTokenType $tokenType = ApiTokenType::PERSONAL_ACCESS_TOKEN) diff --git a/src/State/CurrentApiTokenProvider.php b/src/State/CurrentApiTokenProvider.php new file mode 100644 index 00000000..7011f4f9 --- /dev/null +++ b/src/State/CurrentApiTokenProvider.php @@ -0,0 +1,51 @@ +. + */ + +declare(strict_types=1); + + +namespace App\State; + +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use ApiPlatform\State\ProviderInterface; +use App\Security\ApiTokenAuthenticatedToken; +use Symfony\Bundle\SecurityBundle\Security; + + +class CurrentApiTokenProvider implements ProviderInterface +{ + + public function __construct(private readonly Security $security) + { + + } + + public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + $securityToken = $this->security->getToken(); + if (!$securityToken instanceof ApiTokenAuthenticatedToken) { + return null; + } + + return $securityToken->getApiToken(); + } +} \ No newline at end of file