Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by SensioLabs
  1. Home
  2. Documentation
  3. Cookbook
  4. Security
  5. How to secure any Service or Method in your Application
  • Documentation
  • Book
  • Reference
  • Bundles
  • Cloud
  • Securing Methods Using Annotations

How to secure any Service or Method in your Application

Edit this page

Warning: You are browsing the documentation for Symfony 2.0, which is no longer maintained.

Read the updated version of this page for Symfony 6.3 (the current stable version).

How to secure any Service or Method in your Application

In the security chapter, you can see how to secure a controller by requesting the security.context service from the Service Container and checking the current user's role:

1
2
3
4
5
6
7
8
9
10
11
// ...
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

public function helloAction($name)
{
    if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) {
        throw new AccessDeniedException();
    }

    // ...
}

You can also secure any service in a similar way by injecting the security.context service into it. For a general introduction to injecting dependencies into services see the Service Container chapter of the book. For example, suppose you have a NewsletterManager class that sends out emails and you want to restrict its use to only users who have some ROLE_NEWSLETTER_ADMIN role. Before you add security, the class looks something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
// src/Acme/HelloBundle/Newsletter/NewsletterManager.php
namespace Acme\HelloBundle\Newsletter;

class NewsletterManager
{

    public function sendNewsletter()
    {
        // ... where you actually do the work
    }

    // ...
}

Your goal is to check the user's role when the sendNewsletter() method is called. The first step towards this is to inject the security.context service into the object. Since it won't make sense not to perform the security check, this is an ideal candidate for constructor injection, which guarantees that the security context object will be available inside the NewsletterManager class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace Acme\HelloBundle\Newsletter;

use Symfony\Component\Security\Core\SecurityContextInterface;

class NewsletterManager
{
    protected $securityContext;

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

    // ...
}

Then in your service configuration, you can inject the service:

1
2
3
4
5
6
7
8
# src/Acme/HelloBundle/Resources/config/services.yml
parameters:
    newsletter_manager.class: Acme\HelloBundle\Newsletter\NewsletterManager

services:
    newsletter_manager:
        class:     "%newsletter_manager.class%"
        arguments: ["@security.context"]
1
2
3
4
5
6
7
8
9
10
<!-- src/Acme/HelloBundle/Resources/config/services.xml -->
<parameters>
    <parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</parameter>
</parameters>

<services>
    <service id="newsletter_manager" class="%newsletter_manager.class%">
        <argument type="service" id="security.context"/>
    </service>
</services>
1
2
3
4
5
6
7
8
9
10
// src/Acme/HelloBundle/Resources/config/services.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

$container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager');

$container->setDefinition('newsletter_manager', new Definition(
    '%newsletter_manager.class%',
    array(new Reference('security.context'))
));

The injected service can then be used to perform the security check when the sendNewsletter() method is called:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace Acme\HelloBundle\Newsletter;

use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\SecurityContextInterface;
// ...

class NewsletterManager
{
    protected $securityContext;

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

    public function sendNewsletter()
    {
        if (false === $this->securityContext->isGranted('ROLE_NEWSLETTER_ADMIN')) {
            throw new AccessDeniedException();
        }

        // ...
    }

    // ...
}

If the current user does not have the ROLE_NEWSLETTER_ADMIN, they will be prompted to log in.

Securing Methods Using Annotations

You can also secure method calls in any service with annotations by using the optional JMSSecurityExtraBundle bundle. This bundle is included in the Symfony2 Standard Distribution.

To enable the annotations functionality, tag the service you want to secure with the security.secure_service tag (you can also automatically enable this functionality for all services, see the sidebar below):

1
2
3
4
5
6
7
8
# src/Acme/HelloBundle/Resources/config/services.yml
# ...

services:
    newsletter_manager:
        # ...
        tags:
            -  { name: security.secure_service }
1
2
3
4
5
6
7
8
9
<!-- src/Acme/HelloBundle/Resources/config/services.xml -->
<!-- ... -->

<services>
    <service id="newsletter_manager" class="%newsletter_manager.class%">
        <!-- ... -->
        <tag name="security.secure_service" />
    </service>
</services>
1
2
3
4
5
6
7
8
9
10
// src/Acme/HelloBundle/Resources/config/services.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

$definition = new Definition(
    '%newsletter_manager.class%',
    array(new Reference('security.context'))
));
$definition->addTag('security.secure_service');
$container->setDefinition('newsletter_manager', $definition);

You can then achieve the same results as above using an annotation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace Acme\HelloBundle\Newsletter;

use JMS\SecurityExtraBundle\Annotation\Secure;
// ...

class NewsletterManager
{

    /**
     * @Secure(roles="ROLE_NEWSLETTER_ADMIN")
     */
    public function sendNewsletter()
    {
        // ...
    }

    // ...
}

Note

The annotations work because a proxy class is created for your class which performs the security checks. This means that, whilst you can use annotations on public and protected methods, you cannot use them with private methods or methods marked final.

The JMSSecurityExtraBundle also allows you to secure the parameters and return values of methods. For more information, see the JMSSecurityExtraBundle documentation.

Activating the Annotations Functionality for all Services

When securing the method of a service (as shown above), you can either tag each service individually, or activate the functionality for all services at once. To do so, set the secure_all_services configuration option to true:

1
2
3
4
# app/config/config.yml
jms_security_extra:
    # ...
    secure_all_services: true
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:acme_hello="http://www.example.com/symfony/schema/"
    xsi:schemaLocation="http://www.example.com/symfony/schema/ http://www.example.com/symfony/schema/hello-1.0.xsd">

    <!-- app/config/config.xml -->

    <jms_security_extra secure_controllers="true" secure_all_services="true" />

</srv:container>
1
2
3
4
5
6
// app/config/config.php
$container->loadFromExtension('jms_security_extra', array(
    // ...

    'secure_all_services' => true,
));

The disadvantage of this method is that, if activated, the initial page load may be very slow depending on how many services you have defined.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version
    We stand with Ukraine.
    Version:
    Save your teams and projects before they sink

    Save your teams and projects before they sink

    Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).

    Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).

    Symfony footer

    ↓ Our footer now uses the colors of the Ukrainian flag because Symfony stands with the people of Ukraine.

    Avatar of David Buchmann, a Symfony contributor

    Thanks David Buchmann (@dbu) for being a Symfony contributor

    87 commits • 6.27K lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • Symfony at a Glance
      • Symfony Components
      • Case Studies
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • SymfonyConnect
      • Support
      • How to be Involved
      • Code of Conduct
      • Events & Meetups
      • Projects using Symfony
      • Downloads Stats
      • Contributors
      • Backers
    • Blog

      • Events & Meetups
      • A week of symfony
      • Case studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Documentation
      • Living on the edge
      • Releases
      • Security Advisories
      • SymfonyInsight
      • Twig
      • SensioLabs
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Deployed on

    Follow Symfony

    Search by Meilisearch