如何修复选民必须实现VoterInterface错误

时间:2019-05-25 14:30:51

标签: symfony

Symfony无法识别我的Voter类。建议我实现已经实现的VoterInterface。

我都实现了VoterInterface并扩展了Voter类

services.yml
parameters:
    admin_mail: manager@example.com
services:
    # default configuration for services in *this* file
    _defaults:
        # automatically injects dependencies in your services
        autowire: true
        # automatically registers your services as commands, event subscribers, etc.
        autoconfigure: true
        # this means you cannot fetch services directly from the container via $container->get()
        # if you need to do this, you can override this setting on individual services
        public: false
        bind:
            $adminMail: 'manager@example.com'
            $requestLogger: '@monolog.logger.request'
            Psr\Log\LoggerInterface: '@monolog.logger.request'

    AppBundle\:
        resource: '../../src/AppBundle/*'
        # you can exclude directories or files
        # but if a service is unused, it's removed anyway
        exclude: '../../src/AppBundle/{Entity,Repository,Tests}'

    # controllers are imported separately to make sure they're public
    # and have a tag that allows actions to type-hint services
    AppBundle\Controller\:
        resource: '../../src/AppBundle/Controller'
        public: true
        tags: ['controller.service_arguments']

    app.form_login_authenticator:
        class: AppBundle\Security\FormLoginAuthenticator
        arguments: ["@router", "@security.password_encoder"]

    app.post_entity:
        class: AppBundle\Entity\Post
        arguments: ['@security.helper']

    app.post_voter:
        class: AppBundle\Security\PostVoter
        arguments: ['@security.access.decision_manager']
        tags:
            - { name: security.voter }


security.yml

security:
    encoders:
        AppBundle\Entity\User:
            algorithm: bcrypt
    # https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
    providers:
        in_memory:
            memory:
                users:
                    ryan:
                        password: ryanpass
                        roles: 'ROLE_USER'
                    admin:
                        password: kitten
                        roles: 'ROLE_ADMIN'
        database_users:
            entity:
                class: AppBundle:User
                property: username

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            anonymous: ~
            form_login:
                login_path: login
                check_path: login
                username_parameter: _username
            logout:
                path: /logout
                target: /login
                invalidate_session: true
            provider: database_users
            logout_on_user_change: true

    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, roles: ROLE_USER }

    access_decision_manager:
        strategy: unanimous
        allow_if_all_abstain: false


PostVoter.php

<?php

namespace AppBundle\Security;

use AppBundle\Entity\Post;
use AppBundle\Entity\User;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;

class PostVoter extends Voter implements VoterInterface
{
    const VIEW = 'view';
    const EDIT = 'edit';
    const DELETE = 'delete';

    private $decisionManager;

    public function __construct(AccessDecisionManagerInterface $decisionManager)
    {
        $this->decisionManager = $decisionManager;
    }

    protected function supports($attribute, $subject)
    {
        if (!in_array($attribute, [self::VIEW, self::EDIT, self::DELETE])) {
            return true;
        }

        if (!$subject instanceof Post) {
            return false;
        }

        return true;
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        $user = $token->getUser();

        if (!$user instanceof User) {
            return false;
        }

        $post = $subject;

        switch($attribute) {
            case self::VIEW:
                return $this->canView($post, $user);
            case self::EDIT:
                return $this->canEdit($post, $user);
            case self::DELETE:
                return $this->canDelete($post, $user);
        }

        throw new \LogicException('This code should not be reached!');
    }

    private function canView(Post $post, User $user)
    {
        if ($this->canEdit($post, $user)) {
            return true;
        }

        return !$post->isPrivate();
    }

    private function canEdit(Post $post, User $user)
    {
        return $user->isEqualTo($post->getUser());
    }

    private function canDelete(Post $post, User $user)
    {
        return canEdit($user, $post);
    }

    public function vote(TokenInterface $token, $subject, $attributes)
    {

        foreach ($attributes as $attribute) {
            if (!$this->supports($attribute, $subject) && $this->voteOnAttribute($attribute, $subject)) {
                return VoterInterface::ACCESS_DENIED;
            }
        }
        return VoterInterface::ACCESS_GRANTED;

    }

}


PostController.php

<?php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use AppBundle\Entity\Post;
use AppBundle\Entity\Comment;
use AppBundle\Entity\User;
use AppBundle\Form\PostType;
use AppBundle\Updates\SiteUpdateManager;
use AppBundle\Form\CommentType;


class PostController extends Controller
{   


    public function indexAction(SiteUpdateManager $siteUpdateManager)
    {   
        $repository = $this->getDoctrine()->getManager()->getRepository('AppBundle:Post');

        $posts = $repository->findAllPostWithCommentOrderedByIdDesc();

        $post = new Post();

        $form = $this->createForm(PostType::class, $post);


        return $this->render('post/index.html.twig', [
            'posts' => $posts,
            'form' => $form->createView()
            ]);


    }

    public function showAction(Post $post)
    {
        $this->denyAccessUnlessGranted('view', $post);
    }

    public function updateAction()
    {

    }

    public function newAction(Request $request)
    {
        $post = new Post();

        $form = $this->createForm(PostType::class, $post);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid())
        {   

            $image = $post->getImage();
            $imageName = $this->generateUniqueFileName(). '.' . $image->guessExtension();
            try {
                $image->move(
                    $this->getParameter('post_image_directory'),
                    $imageName
                );
            } catch (FileException $e) {
                return new Response('File upload error: '.$e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
            }
            $post->setUser($this->get('security.token_storage')->getToken()->getUser());
            $post->setImage($imageName);
            $em = $this->getDoctrine()->getManager();
            $em->persist($post);
            $em->flush();
            return $this->redirectToRoute('post_list');
        }

        return $this->render('post/new.html.twig', [
            'form' => $form->createView()
        ]);    
    }

    public function deleteAction(Post $post)
    {   
        $this->denyAccessUnlessGranted('delete', $post);
        $em = $this->getDoctrine()->getManager();
        $em->remove($post);
        $em->flush();

        return $this->redirectToRoute('post_list');

    }

    public function generateUniqueFileName()
    {
        return sha1(uniqid(mt_rand(), true));
    }

}             

Post.php

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\User;
use AppBundle\Entity\Comment;
use Symfony\Component\Security\Core\Security;

class Post
{
    private $id;
    private $title;
    private $description;
    private $image;
    private $comments;
    private $user;

    private $security;



    public function __construct(Security $security)
    {
        $this->comments = new ArrayCollection();
        $this->security = $security;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getDescription()
    {
        return $this->description;
    }

    public function setDescription($description)
    {
        $this->description = $description;
    }

    public function getImage()
    {
        return $this->image;
    }

    public function setImage($image)
    {
        $this->image = $image;
    }

    public function getUser()
    {
        return $this->user;
    }

    public function setUser(User $user)
    {
        $this->user = $user;
    }

    public function getComments()
    {
        return $this->comments;
    }

    public function addComment(Comment $comment)
    {
        $this->comments[] = $comment;
    }

    public function isPrivate()
    {   
        return in_array("ROLE_USER", $this->security->getUser()->getRoles());
        return $this->getUser()->isEqualTo($this->security->getUser());
    }

}

User.php

<?php

namespace AppBundle\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\Post;
use AppBundle\Entity\Comment;
use Symfony\Component\Security\Core\User\EquatableInterface;

class User implements UserInterface, EquatableInterface
{
    private $id;
    private $email;
    private $username;
    private $roles;
    private $plainPassword;
    private $password;
    private $posts;
    private $comments;


    public function __construct()
    {
        $this->roles = ['ROLE_USER'];
        $this->posts = new ArrayCollection();
        $this->comments = new ArrayCollection();
    }

    public function eraseCredentials()
    {
    }

    public function getRoles()
    {
        return $this->roles;
    }

    public function getId()
    {
        return $this->id;
    }

    public function setUsername($username)
    {
        return $this->username = $username;
    }

    public function getUsername()
    {
        return $this->username;
    }

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }

    public function getPassword()
    {
        return $this->password;
    }

    public function setPassword($password)
    {
        $this->password = $password;
    }

    public function getPlainPassword()
    {
        return $this->plainPassword;
    }

    public function setPlainPassword($plainPassword)
    {
        $this->plainPassword = $plainPassword;
    }

    public function getSalt()
    {
        return null;
    }

    public function getComments()
    {
        return $this->comments;
    }

    public function addComment(Comment $comment)
    {
        $this->comments[] = $comment;
    }

    public function getPosts()
    {
        return $this->posts;
    }

    public function addPost(Post $post)
    {
        $this->posts[] = $post;
    }


    public function isEqualTo(UserInterface $user) {
        if (!$user instanceof User) {
            return false;
        }

        if ($this->getUsername() !== $user->getUsername()) {
            return false;
        }

        if ($this->getPassword() !== $user->getPassword()) {
            return false;
        }

        return true;
    }

}

AppBundle \ Security \ PostVoter应该实现Symfony \ Component \ Securi
  ty \ Core \ Authorization \ Voter \ VoterInterface接口用作选民。

0 个答案:

没有答案