我发布这个解决方案是为了让其他人可以看到我的最终代码,但这里是我在按照有问题的建议实施 Voter 时发现的缺陷。
supportsAttribute:似乎当您在SecurityContext 上调用isGranted 方法时,它实际上并没有在将vote 调用委托给VoterInterface 之前检查此方法,所以在您的 vote 方法中,您实际上必须自己检查属性。
supportsClass:在上面有问题的回答中,这种方法似乎是基于工厂的选择的关键,VoterInterfaces 可以投票,但实际上 symfony2 文档显示:
supportsClass() 方法用于检查投票者是否支持当前用户令牌类。
因此,它实际上似乎与Voter 是否支持令牌类型有关。更糟糕的是,PHP Doc 似乎含糊不清:
检查选民是否支持给定的类。
无论如何,主要问题是在将调用委托给任何选民的vote 方法之前,SecurityContext 永远不会检查此方法 - 即使此方法被硬编码为 @987654331 @vote 仍然会被调用!
所以基本上这个故事的寓意似乎是:手动检查 $attributes 和 $object 进入 vote 方法。
我的代码:
services.yml
parameters:
comment_voter.class: Acme\Bundle\CommentBundle\Security\Authorization\Voter\CommentVoter
services:
comment_voter:
class: %comment_voter.class%
arguments: [@service_container]
public: false
tags:
- { name: security.voter }
和选民类别:
<?php
namespace Acme\Bundle\CommentBundle\Security\Authorization\Voter;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Acme\Bundle\CommentBundle\Entity\Comment;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* A class to check editing privileges for Comments.
*/
class CommentVoter implements VoterInterface {
const AUTHOR_EDIT_TIME_LIMIT = 300;
private $container;
public function __construct($container) {
$this->container = $container;
}
public function supportsAttribute($attribute) {
return $attribute === 'EDIT';
}
public function supportsClass($class) {
return true;
}
/**
* Checks whether or not the current user can edit a comment.
*
* Users with the role ROLE_COMMENT_MODERATOR may always edit.
* A comment's author can only edit within 5 minutes of it being posted.
*
* {@inheritdoc}
*/
public function vote(TokenInterface $token, $object, array $attributes) {
if ( !($object instanceof Comment) ) {
return VoterInterface::ACCESS_ABSTAIN;
}
// Only supports 'EDIT' for now.
if ( !$this->supportsAttribute($attributes[0]) ) {
return VoterInterface::ACCESS_ABSTAIN;
}
$user = $token->getUser();
if ( !($user instanceof UserInterface) ) {
return VoterInterface::ACCESS_DENIED;
}
// Is the token a comment moderator?
if ( $this->container->get('security.context')->isGranted('ROLE_COMMENT_MODERATOR') ) {
return VoterInterface::ACCESS_GRANTED;
}
// Is the token the author of the post and within the edit window.
$originalRevision = $object->getOriginalRevision();
if ( $originalRevision->getAuthor()->equals($user) ) {
if (
(time() - $originalRevision->getCreationDate()->getTimestamp())
<= self::AUTHOR_EDIT_TIME_LIMIT
) {
return VoterInterface::ACCESS_GRANTED;
}
}
return VoterInterface::ACCESS_DENIED;
}
}
最后是模板:
{% if is_granted('EDIT', comment) %}<a href="#">Edit</a>{% endif %}
我希望这对将来的其他人有所帮助,非常感谢 Problematic 为我指明了 Voters 的方向。