Я создаю приложение-песочницу как практику на платформе Api, и мне нужно решить следующую проблему:
Давайте рассмотрим следующую конечную точку REST для пользовательской сущности:
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ в примерах кода там немного больше атрибутов, но вся концепция применима в отношении этого
Collection-get (aka. / api / users) - доступно только для администраторов (все атрибуты доступны, может быть, мы исключаем хэширование пароль)
POST - каждый должен иметь доступ к следующим атрибутам: имя пользователя, электронная почта, plainPassword (не сохраняется на случай, если кто-то спросит)
PATCH / PUT - здесь все становится довольно сложно: я хочу, чтобы те, у кого ROLE_ADMIN, имели доступ к полям username, email, plainPassword. А те, кто является владельцами, могут изменять только plainPassword
DELETE - только ROLE_ADMIN и владельцы могут удалять
Я начну с конфигурации ресурса
resources:
App\Entity\User:
# attributes:
# normalization_context:
# groups: ['read', 'put', 'patch', 'post', 'get', 'collection:get']
# denormalization_context:
# groups: ['read', 'put', 'patch', 'post', 'get', 'collection:get']
collectionOperations:
get:
security: 'is_granted("ROLE_ADMIN")'
normalization_context: { groups: ['collection:get'] }
post:
normalization_context: { groups: ['admin:post', 'post'] }
itemOperations:
get:
normalization_context: { groups: ['admin:get', 'get'] }
security: 'is_granted("ROLE_ADMIN") or object == user'
put:
normalization_context: { groups: ['admin:put', 'put'] }
security: 'is_granted("ROLE_ADMIN") or object == user'
patch:
normalization_context: { groups: ['admin:patch', 'patch'] }
security: 'is_granted("ROLE_ADMIN") or object == user'
delete:
security: 'is_granted("ROLE_ADMIN") or object == user'
Вот конфигурация сериализатора
App\Entity\User:
attributes:
username:
groups: ['post', 'admin:put', 'admin:patch', 'collection:get', 'get']
email:
groups: ['post', 'admin:put', 'admin:patch', 'collection:get', 'get']
firstName:
groups: ['post', 'admin:put', 'admin:patch', 'collection:get', 'get']
lastName:
groups: ['post', 'admin:put', 'admin:patch', 'collection:get', 'get']
plainPassword:
groups: ['post', patch]
createdAt:
groups: ['get', 'collection:get']
lastLoginDate:
groups: ['get', 'collection:get']
updatedAt:
groups: ['collection:get']
Вот построитель контекстной группы (Зарегистрирован как сервис, как указано в API-платформе: c
<?php
namespace App\Serializer;
use Symfony\Component\HttpFoundation\Request;
use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
final class AdminContextBuilder 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);
if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) {
switch($request->getMethod()) {
case 'GET':
$context['groups'][] = 'admin:get';
break;
case 'POST':
$context['groups'][] = 'admin:post';
case 'PUT':
$context['groups'][] = 'admin:put';
case 'PATCH':
$context['groups'][] = 'admin:patch';
}
}
return $context;
}
}
проблема в том, что даже если я вошел в систему как пользователь только с ROLE_USER, я все еще могу изменить поле имени пользователя, которое должно быть заблокировано в соответствии с группой нормализации admin: patch. Я довольно новичок в api-платформе и не могу Я вполне понимаю, почему это не работает, но я думаю, что возникнет проблема с конструктором контекста. Спасибо за вашу помощь, я буду держать вопрос в курсе, если я что-нибудь придумаю тем временем