Symfony 如何在控制器中安全地调用删除操作?
我创建了一个带有评论系统的博客,我希望作者或管理员删除他的评论 所以我搜索了互联网,但我只找到了关于Symfony 2/3的帖子,我很难理解 所以我创建了自己的函数Symfony 如何在控制器中安全地调用删除操作?,symfony,symfony-forms,symfony4,symfony-4.2,Symfony,Symfony Forms,Symfony4,Symfony 4.2,我创建了一个带有评论系统的博客,我希望作者或管理员删除他的评论 所以我搜索了互联网,但我只找到了关于Symfony 2/3的帖子,我很难理解 所以我创建了自己的函数 /** * @Route("/blog/commentDelete/{id}-{articleId}-{articleSlug}", name="comment_delete") */ public function commentDelete($id, $articleId, $articleSlug, CommentRepo
/**
* @Route("/blog/commentDelete/{id}-{articleId}-{articleSlug}", name="comment_delete")
*/
public function commentDelete($id, $articleId, $articleSlug, CommentRepository $commentRepository, AuthorizationCheckerInterface $authChecker){
$em = $this->getDoctrine()->getManager();
$comment = $commentRepository->find($id);
$user = $this->getUser();
if ($user->getId() != $comment->getAuthor()->getId() && $authChecker->isGranted('ROLE_MODERATOR') == false ){
throw exception_for("Cette page n'existe pas");
}
$em->remove($comment);
$em->flush();
$this->addFlash('comment_success', 'Commentaire supprimé avec succès');
return $this->redirectToRoute('blog_show', array('id' => $articleId, 'slug' => $articleSlug));
}
在twig上,我有以下链接:
<a href="{{ path('comment_delete', {'id': comment.id, 'articleId': article.id, 'articleSlug': article.slug}) }}">Supprimer</a>
我需要操作的注释id,以及删除注释后的article id et article slug重定向用户
我检查删除评论的人是作者还是版主
然而,我听说这是绝对不安全的,因为我必须使用表单,但我真的不知道在这种情况下如何使用表单。。。或者使用JS隐藏指向最终用户的链接
因此,我想知道我的功能是否足够安全,或者是否存在更好的解决方案,以及如何实现它?为了解决此类问题,我建议使用Symfony投票者您正朝着正确的方向前进。始终在后端执行验证和权限检查 隐藏链接或使用表单并将其设置为禁用不会阻止使用开发工具的用户向控制器发送请求。我更愿意将前端检查视为用户的一种便利——在发出请求之前,直接向用户显示某些数据无效/不允许他们执行某些操作 我正在使用SensioFrameworkExtraBundle进行角色检查(我仍然不喜欢这种检查的注释..hmm)-如果用户没有合适的角色进行控制器操作,则抛出permissionDeniedException。
接下来可能需要执行进一步的检查,就像使用
$user->getId()!=$comment->getAuthor()->getId()
保护删除操作的一种方法是执行以下操作:
- 正如Victor Kochkarev所说,您可以根据此文档创建一个投票者
- 在模板中,可以执行以下操作:
我认为这是一个解决方案的尝试。为什么不在删除按钮上实现一个js
confirm
?(我的意思是,将其设置为一个按钮,并在click事件上放置一个eventhandler,以运行确认
函数,只有在返回真
时才删除。)这是一个解释更好的网站,使用表单(或HTTPPOST
)代替链接并不更安全。隐藏链接不会保护任何东西。它被调用,不应该被使用。我不想实现确认,我希望我的评论被直接删除。Ferdanator所以我的功能是好的和安全的?例如,谷歌机器人可以用这种方法删除评论吗?你可以使用表单和post方法,并添加csrf保护。要检查删除评论的人是否是作者或版主,另一种方法是使用symfony voter,以便您可以在控制器方法中使用它来保护操作,并在细枝模板中为无权访问的用户隐藏表单。由于各种原因,StackOverflow强烈反对仅链接答案。如果你没有时间发布一个完整的答案(就像wiliam bridge那样),你可以把它作为一个评论(当你达到所需的50点声誉时)。请查看整个帮助部分,了解SO的工作原理:-)
<?php
namespace App\Security\Voter;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use App\Entity\Comment;
class CommentVoter extends Voter
{
const CAN_DELETE = 'CAN_DELETE';
protected function supports($attribute, $subject)
{
return in_array($attribute, [self::CAN_DELETE]) && $subject instanceof Comment;
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$user = $token->getUser();
// if the user is anonymous, do not grant access
if (!$user instanceof User) {
return false;
}
/** @var Comment $comment */
$comment = $subject;
switch ($attribute) {
case self::CAN_DELETE:
return $this->canDelete($comment, $user);
}
throw new \LogicException('This code should not be reached!');
}
private function canDelete(Comment $comment, User $user)
{
if($user->getId() !== $comment->getAuthor()->getId() && $user->hasRole('ROLE_MODERATOR') === false) {
return false;
}
return true;
}
}
/**
* @param string $role
*/
public function hasRole(string $role)
{
return in_array(strtoupper($role), $this->getRoles(), true);
}
{% if is_granted('CAN_DELETE', comment) %}
<form action="{{ path('comment_delete', {'id': comment.id, 'articleId': article.id, 'articleSlug': article.slug}) }}" method="post">
<input type="hidden" name="_csrf_token" value="{{csrf_token('delete_comment')}}" />
<button>supprimer</button>
</form>
{% endif %}
/**
* @Route("/blog/commentDelete/{id}-{articleId}-{articleSlug}", methods={"POST"}, name="comment_delete")
*/
public function commentDelete($id, $articleId, $articleSlug, CommentRepository $commentRepository, EntityManagerInterface $em){
$comment = $commentRepository->find($id);
$csrfToken = $request->request->get('_csrf_token');
if(!$this->isCsrfTokenValid('delete_comment', $csrfToken) || !$this->isGranted('CAN_DELETE', $comment){
throw exception_for("Cette page n'existe pas");
}
$em->remove($comment);
$em->flush();
$this->addFlash('comment_success', 'Commentaire supprimé avec succès');
return $this->redirectToRoute('blog_show', array('id' => $articleId, 'slug' => $articleSlug));
}