Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Deny Access in the Controller

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

There are two main places where you can deny access. The first we just learned about: access_control in security.yaml:

security:
... lines 2 - 40
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
... lines 43 - 44

It's simple - just a regular expression and a role. It's the best way to protect entire areas of your site - like everything under /admin with ROLE_ADMIN.

I do use access controls for things like that. But, most of the time, I prefer to control access at a more granular level. Open CommentAdminController. Most of the time, I deny access right inside the controller.

To test this out - let's comment-out our access control:

security:
... lines 2 - 40
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN }
... lines 43 - 44

Back in CommentAdminController, how can we deny access here? Simple: $this->denyAccessUnlessGranted() and pass this a role: ROLE_ADMIN:

... lines 1 - 10
class CommentAdminController extends Controller
{
... lines 13 - 15
public function index(CommentRepository $repository, Request $request, PaginatorInterface $paginator)
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
... lines 19 - 32
}
}

That's it. Move over and refresh!

Nice! Try changing it to ROLE_USER:

... lines 1 - 10
class CommentAdminController extends Controller
{
... lines 13 - 15
public function index(CommentRepository $repository, Request $request, PaginatorInterface $paginator)
{
$this->denyAccessUnlessGranted('ROLE_USER');
... lines 19 - 32
}
}

Access granted! I love it!

IsGranted Annotation

But wait, there's more! As simple as this is, I like to use annotations. Check this out: delete the denyAccessUnlessGranted() code. Instead, above the method, add @IsGranted() to use an annotation that comes from SensioFrameworkExtraBundle: a bundle that we installed a long time ago via composer require annotations. In double quotes, pass ROLE_ADMIN:

... lines 1 - 6
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
... lines 8 - 11
class CommentAdminController extends Controller
{
/**
... line 15
* @IsGranted("ROLE_ADMIN")
*/
public function index(CommentRepository $repository, Request $request, PaginatorInterface $paginator)
{
... lines 20 - 32
}
}

Nice! Try it: refresh!

Access Denied by controller annotation

Pretty sweet. I know not everyone will love using annotations for this. So, if you don't love it, use the PHP version. No problem.

Protecting an Entire Controller Class

Oh, but the annotation does have one superpower. In addition to putting @IsGranted above a controller method, you can also put it above the controller class. Above CommmentAdminController, add @IsGranted("ROLE_ADMIN"):

... lines 1 - 6
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
... lines 8 - 11
/**
* @IsGranted("ROLE_ADMIN")
*/
class CommentAdminController extends Controller
{
... lines 17 - 35
}

Now, every method inside of this controller... which is only one right now, will require this role. When you refresh... yep! Same error. That is an awesome way to deny access.

We know how to make sure a user has a role. But, how can we simply make sure a user is logged in, regardless of roles? Let's find out next - and - create our first admin users.

Leave a comment!

12
Login or Register to join the conversation
Farshad Avatar
Farshad Avatar Farshad | posted 2 years ago

How does ROLE_ADMIN look like in the database role column? Is it litterly a string called 'ROLE_ADMIN'? Or is ROLE_ADMIN a const somewhere?

Reply

Hey Farry7,

Haha, good question! :D That you can also easily check it yourself... didn't you download the course code and follow the tutorials coding along with us? ;) ROLE_ADMIN is literally ROLE_ADMIN string in the DB on the user record, but because user may have a few roles - roles are stored as array that is serialized to string to store in the DB :) ROLE_ADMIN is just an arbitrary name, you can come up with any string, e.g. ROLE_ADMINISTRATOR.

Cheers!

1 Reply
Default user avatar
Default user avatar CcC Mehmet | posted 4 years ago

wow nice!!!

Reply
Peter-K Avatar
Peter-K Avatar Peter-K | posted 4 years ago

Annotation @IsGranted can I somehow use it on multiple roles?

I have tried @IsGranted(["ROLE_ADMIN","ROLE_MANAGER"]) but this doesnt work.

I would like to check if the user has at least 1 of the roles.

Reply
Peter-K Avatar

btw ryan you have to update email just saw it in IsGranted.php :)

Reply

Hey Peter K.!

Good question! You can use multiple roles *anywhere* in Symfony - the IsGranted() annotation, denyAccessUnlessGranted, and even in access_control I believe. But, I never do this, because, for me, it's not clear what passing 2 roles means. Is it an "OR" (ROLE_ADMIN or ROLE_MANAGER) or an "AND". The answer is "OR", but because it's not clear to look at, I don't prefer using it (https://github.com/symfony/.... Instead, I rely on role_hierarchy - i would probably give ROLE_ADMIN the ROLE_MANAGER role in the hierarchy. But, it depends on your needs - there is certainly nothing wrong with passing multiple roles :).

> btw ryan you have to update email just saw it in IsGranted.php :)

What do you mean? What email? :)

Cheers!

Reply

Oh, and I just realized I misread your first comment! IsGranted with multiple roles is NOT working? It should - it should have the same affect as passing denyAccessUnlessGranted() those same 2 roles. What are you seeing?

Cheers!

Reply
Peter-K Avatar
Peter-K Avatar Peter-K | weaverryan | posted 4 years ago | edited

when using this:


/**
 * @IsGranted(["ROLE_ADMIN","ROLE_MANAGER"])
 */

error:


Exception thrown when handling an exception (Symfony\Component\Config\Exception\FileLoaderLoadException: [Syntax Error] Expected PlainValue, got '[' at position 11 in class App\Controller\ResourcePlanningController in /Users/peterkosak/Desktop/symfony/test/config/routes/../../src/Controller/ (which is being imported from "/Users/peterkosak/Desktop/symfony/test/config/routes/annotations.yaml"). Make sure annotations are installed and enabled.)

when using without square [


/**
 * @IsGranted("ROLE_ADMIN","ROLE_MANAGER")
 */

getting this


Exception thrown when handling an exception (Symfony\Component\Config\Exception\FileLoaderLoadException: [Syntax Error] Expected Value, got 'ROLE_MANAGER' at position 24 in class App\Controller\ResourcePlanningController in /Users/peterkosak/Desktop/symfony/test/config/routes/../../src/Controller/ (which is being imported from "/Users/peterkosak/Desktop/symfony/test/config/routes/annotations.yaml"). Make sure annotations are installed and enabled.)

Reply
Peter-K Avatar

it is screaming about annotation not installed but when I use only 1 role in annotation I will get Access Denied

Reply

Try this syntax:


/**
 * @IsGranted({"ROLE_ADMIN","ROLE_MANAGER"})
 */

If I remember correctly, you always use { } in annotations, never [ ] (even if it's an index array). If you'r egetting an error about the annotation not being installed, make sure you have the use statement for it:


use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;

The php-annotations plugin in PhpStorm auto-adds this for me when I auto-complete the annotation :).

Cheers!

1 Reply

> btw ryan you have to update email just saw it in IsGranted.php :)

Ohh. I understand now! Yep, I'll probably have a lot of knpuniversity.com email addresses around in the code for a long time :p. But, that email does still work ;).

1 Reply
Peter-K Avatar

Yeaha, curly brackets work :) Thank you.

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
        "knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
        "knplabs/knp-time-bundle": "^1.8", // 1.8.0
        "nexylan/slack-bundle": "^2.0,<2.2.0", // v2.0.0
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.2.0
        "stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
        "symfony/asset": "^4.0", // v4.1.4
        "symfony/console": "^4.0", // v4.1.4
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/framework-bundle": "^4.0", // v4.1.4
        "symfony/lts": "^4@dev", // dev-master
        "symfony/orm-pack": "^1.0", // v1.0.6
        "symfony/security-bundle": "^4.0", // v4.1.4
        "symfony/serializer-pack": "^1.0", // v1.0.1
        "symfony/twig-bundle": "^4.0", // v4.1.4
        "symfony/web-server-bundle": "^4.0", // v4.1.4
        "symfony/yaml": "^4.0", // v4.1.4
        "twig/extensions": "^1.5" // v1.5.2
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.0.2
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.7
        "fzaninotto/faker": "^1.7", // v1.8.0
        "symfony/debug-bundle": "^3.3|^4.0", // v4.1.4
        "symfony/dotenv": "^4.0", // v4.1.4
        "symfony/maker-bundle": "^1.0", // v1.7.0
        "symfony/monolog-bundle": "^3.0", // v3.3.0
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.1.4
        "symfony/profiler-pack": "^1.0", // v1.0.3
        "symfony/var-dumper": "^3.3|^4.0" // v4.1.4
    }
}
userVoice