简体   繁体   中英

Symfony2, routes and access validator

Let's imagine we have user and posts. Where post link is

localhost/post/{postID}

How can i check on sf2 level security is user owner of this post (and redirect if not)? I know not much solutions but don't want to use then (I don't want discuss here why).

I. Simple check in controller. This one looks like simple check (by service or right in action).

if ($this->isOwner()){
return $this->redirect(...);
}

II. Through EventListener. This case better, but not good, because I need to set on each route specific rule. And this listener will be executed every time, even if it will have checker (do check or not) I don't want this one.

Is there are other solutions for this one.

Also interesting how will it looks like to check 'have user permission to edit\\delete existing post'.

You can create a PostAuthorizer whose task would be to check whether a user can do something on a post or not. For this to work, you can inject a AuthenticatedUserProvider to get the authenticated user straight away in your PostAuthorizer .

1 Create an AuthenticatedUserProvider (I suppose you're using FOSUserBundle like everyone).

<?php

namespace Acme\PostBundle\Security;

use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use FOS\UserBundle\Model\UserInterface;

/**
 * Provides the authenticated user
 */
class AuthenticatedUserProvider
{
    /**
     * The security context
     *
     * @var SecurityContextInterface
     */
    protected $securityContext;

    public function __construct(SecurityContextInterface $securityContext)
    {
        $this->securityContext = $securityContext;
    }

    /**
     * Gets the current authenticated user
     *
     * @return UserInterface
     */
    public function getAuthenticatedUser()
    {
        $user = $this->securityContext->getToken()->getUser();

        if (!$user instanceof UserInterface) {
            throw new AccessDeniedException('Must be logged in with a UserInterface instance');
        }

        return $user;
    }
}

2 And declare it as a service:

services:
    #Authenticated User Provider
    acme_post.autenticated_user.provider:
        class: Acme\PostBundle\Security\AuthenticatedUserProvider
        arguments:
            securityContext: "@security.context"

3 Create a PostAuthorizer

<?php

namespace Acme\PostBundle\Security;

use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Acme\PostBundle\Entity\PostInterface;
use Acme\PostBundle\Security\AuthenticatedUserProvider;

/**
 * Manages permissions to manipulate posts
 */
class PostAuthorizer
{
    /**
     * The user provider
     *
     * @var AuthenticatedUserProvider
     */
    protected $authenticatedUserProvider;

    public function __construct(AuthenticatedUserProvider $authenticatedUserProvider)
    {
        $this->authenticatedUserProvider = $authenticatedUserProvider;
    }

    /**
     * Tells if the current user is allowed
     * to see this post
     *
     * @param PostInterface $post
     * @return boolean
     */
    public function canSeePost(PostInterface $post)
    {
        return ($this->getAuthenticatedUser()->getId()  === $post->getOwner()->getId());
    }

    /**
     * Tells if the current participant is allowed
     * to delete this post
     *
     * @param PostInterface $post
     * @return boolean
     */
    public function canDeletePost(PostInterface $post)
    {
        return $this->canSeePost($post);
    }

    /**
     * Tells if the current participant is allowed
     * to edit this post
     *
     * @param PostInterface $post
     * @return boolean
     */
    public function canEditPost(PostInterface $post)
    {
       return $this->canSeePost($post);
    }

    /**
     * Gets the current authenticated user
     *
     * @return FOS\UserBundle\Model\UserInterface
     */

    protected function getAuthenticatedUser()
    {
        return $this->authenticatedUserProvider->getAuthenticatedUser();
    }
}

4 And declare it as a service

services:
    acme_post.post.authorizer:
        class: Acme\PostBundle\Security\PostAuthorizer
        arguments:
            authenticatedUserProvider: "@acme_post.autenticated_user.provider"

5 Finally, in your controller (or in a post provider if you want), you can simply do this:

if( !$this->container->get('acme_post.post.authorizer')->canSeePost($post) ) {
    throw new AccessDeniedException('You are not allowed to see this post');
}

// can safely display the post now

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM