我有一个用Symfony 3.4创建的网站,在执行操作时,我必须检查当前用户是否可以编辑目标产品,如下所示:
/**
* @Route("/products/{id}/edit")
*/
public function editAction(Request $request, Product $product)
{
// security
$user = $this->getUser();
if ($user != $product->getUser()) {
throw $this->createAccessDeniedException();
}
// ...
}
如何避免对每个动作进行相同的检查(如果使用注释和表达式,则要加分)?
我已经在使用security.yml
和access_control来拒绝基于角色的访问。
答案 0 :(得分:2)
您可以将Voter用于此特定目的。不涉及魔术。创建和注册选民后,将在安全层中自动完成选民身份验证。
您只需要创建Voter类,然后将其注册为服务即可。但是,如果您使用默认的services.yaml配置,则将自动为您注册为服务!
这是您可以使用的示例。您可能需要更改一些项目,但是基本上就是这样。
要了解更多信息,请访问:https://symfony.com/doc/current/security/voters.html
<?php
namespace AppBundle\Security;
use AppBundle\Entity\Product;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use AppBundle\Entity\User;
class ProductVoter extends Voter
{
const EDIT = 'EDIT_USER_PRODUCT';
protected function supports($attribute, $subject)
{
if($attribute !== self::EDIT) {
return false;
}
if(!$subject instanceof Product) {
return false;
}
return true;
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
/** @var Product $product */
$product= $subject;
$user = $token->getUser();
if (!$user instanceof User) {
// the user must be logged in; if not, deny access
return false;
}
return $this->belongsToUser($product, $user);
}
private function belongsToUser(Product $product, User $user)
{
return $user->getId() === $product->getUser()->getId();
}
}
答案 1 :(得分:1)
您可以尝试使用听众:
app.user.listener:
class: AppBundle\EventListener\ValidateUserListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
arguments: ["@service_container", "@doctrine.orm.entity_manager"]
为操作添加了名称“ edit_product”。
/**
*
* @Route("/products/{id}/edit",name="edit_product")
*/
public function editAction()
{
...
<?php
namespace AppBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class ValidateUserListener
{
private $container;
private $entityManager;
public function __construct($container, $entityManager)
{
$this->container = $container;
$this->entityManager = $entityManager;
}
public function onKernelRequest(GetResponseEvent $event)
{
$currentRoute = $event->getRequest()->attributes->get('_route');
if($currentRoute=='edit_product' || $currentRoute=='edit_item' )
{
$array_user = $this->getCurrentUser();
if($array_user['is_auth'])
{
$current_user = $array_user['current_user'];
$product = $this->entityManager->getRepository('AppBundle:User')->findOneByUsername($current_user);
$product_user = $product->getUsername();
if ($current_user !==$product_user)
{
throw $this->createAccessDeniedException();
}
}
}
}
private function getCurrentUser()
{
//Get the current logged User
$user = $this->container->get('security.token_storage')->getToken()->getUser();
if(null!=$user)
{
//If user is authenticated
$isauth = $this->container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY');
return array('is_auth'=>$isauth, 'current_user'=>$user);
}
return array('is_auth'=>false, 'current_user'=>$user);
}
}