8000 Merge branch 'adding_securing_services_recipe' of git://github.com/ri… · phreaknerd/symfony-docs@48dfae0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 48dfae0

Browse files
committed
Merge branch 'adding_securing_services_recipe' of git://github.com/richardmiller/symfony-docs into richardmiller-adding_securing_services_recipe
2 parents 4d668af + 5edcaef commit 48dfae0

File tree

1 file changed

+268
-8
lines changed

1 file changed

+268
-8
lines changed
Lines changed: 268 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,271 @@
11
How to secure any Service or Method in your Application
22
=======================================================
33

4-
This article has not been written yet, but will soon. If you're interested
5-
in writing this entry, see :doc:`/contributing/documentation/overview`.
6-
7-
This entry should show how you can inject the security context into any service
8-
and then protect anything you want. This will likely reference parts from
9-
the service container document and should also tease the SecurityExtraBundle.
10-
Ideally, it should be a somewhat real example that shows the whole process,
11-
including creating the service in the service container configuration.
4+
In the :doc:`/book/security` book pages you can see how to secure
5+
``ContainerAware`` controllers by requesting the ``security.context`` service
6+
from the Service Container and checking the current user's role:
7+
8+
.. code-block:: php
9+
10+
use Symfony\Component\Security\Core\Exception\AccessDeniedException
11+
// ...
12+
13+
public function helloAction($name)
14+
{
15+
if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) {
16+
throw new AccessDeniedException();
17+
}
18+
19+
// ...
20+
}
21+
22+
You can also secure any service in a similar way by injecting the
23+
``security.context`` service into it. For a general introduction to injecting
24+
dependencies into services see the :doc:`/book/service_container` chapter of
25+
the book. For example, you have a ``NewsletterManager`` class for sending out
26+
newsletters and want to restrict its use to only users with the
27+
``ROLE_NEWSLETTER_ADMIN`` role. The class currently looks like this:
28+
29+
.. code-block:: php
30+
31+
namespace Acme\HelloBundle\Newsletter;
32+
33+
class NewsletterManager
34+
{
35+
36+
public function sendNewsletter()
37+
{
38+
//--
39+
}
40+
41+
// ...
42+
}
43+
44+
You want to check the user's role when the ``sendNewsletter()`` method is
45+
called. The first step towards this is to inject the ``security.context``
46+
service into the object. As we require the service it is an ideal candidate
47+
for constructor injection as this makes it a required dependency:
48+
49+
.. code-block:: php
50+
51+
namespace Acme\HelloBundle\Newsletter;
52+
53+
class NewsletterManager
54+
{
55+
protected $securityContext;
56+
57+
public function __construct($securityContext)
58+
{
59+
$this->securityContext = $securityContext;
60+
}
61+
62+
// ...
63+
}
64+
65+
Then in your config you can inject the service:
66+
67+
.. configuration-block::
68+
69+
.. code-block:: yaml
70+
71+
# src/Acme/HelloBundle/Resources/config/services.yml
72+
parameters:
73+
# ...
74+
newsletter_manager.class: Acme\HelloBundle\Newsletter\NewsletterManager
75+
76+
services:
77+
my_mailer:
78+
# ...
79+
newsletter_manager:
80+
class: %newsletter_manager.class%
81+
arguments: [@security.context]
82+
83+
.. code-block:: xml
84+
85+
<!-- src/Acme/HelloBundle/Resources/config/services.xml -->
86+
<parameters>
87+
<!-- ... -->
88+
<parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</parameter>
89+
</parameters>
90+
91+
<services>
92+
<service id="my_mailer" ... >
93+
<!-- ... -->
94+
</service>
95+
<service id="newsletter_manager" class="%newsletter_manager.class%">
96+
<argument type="service" id="security.context"/>
97+
</service>
98+
< A3D4 ;/services>
99+
100+
.. code-block:: php
101+
102+
// src/Acme/HelloBundle/Resources/config/services.php
103+
use Symfony\Component\DependencyInjection\Definition;
104+
use Symfony\Component\DependencyInjection\Reference;
105+
106+
// ...
107+
$container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager');
108+
109+
$container->setDefinition('newsletter_manager', new Definition(
110+
'%newsletter_manager.class%',
111+
array(new Reference('security.context'))
112+
));
113+
114+
The injected service can then be used to perform the security check when the
115+
``sendNewsletter()`` method is called:
116+
117+
.. code-block:: php::
118+
119+
namespace Acme\HelloBundle\Newsletter;
120+
121+
use Symfony\Component\Security\Core\Exception\AccessDeniedException
122+
use Symfony\Component\Security\Core\SecurityContext;
123+
// ...
124+
125+
class NewsletterManager
126+
{
127+
protected $securityContext;
128+
129+
public function __construct(SecurityContext $securityContext)
130+
{
131+
$this->securityContext = $securityContext;
132+
}
133+
134+
public function sendNewsletter()
135+
{
136+
if (false === $this->securityContext->isGranted('ROLE_NEWSLETTER_ADMIN')) {
137+
throw new AccessDeniedException();
138+
}
139+
140+
//--
141+
}
142+
143+
// ...
144+
}
145+
146+
If the current user does not have the ``ROLE_NEWSLETTER_ADMIN`` then they
147+
will be prompted to log in.
148+
149+
Securing Methods Using Annotations
150+
~~~~~~~~~~~~~~~~~~~~~~~~~~
151+
152+
You can also secure method calls in any service using annotations using the
153+
``SecurityExtraBundle`` optional bundle. This is included in the standard
154+
Symfony2 distribution. The default configuration for the
155+
``SecurityExtraBundle`` only secures Controllers and not all services:
156+
157+
.. configuration-block::
158+
159+
.. code-block:: yaml
160+
161+
# app/config/config.yml
162+
jms_security_extra:
163+
secure_controllers: true
164+
secure_all_services: false
165+
166+
.. code-block:: xml
167+
168+
<!-- app/config/config.xml -->
169+
<srv:container xmlns="http://symfony.com/schema/dic/security"
170+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
171+
xmlns:srv="http://symfony.com/schema/dic/services"
172+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
173+
174+
<jms_security_extra secure_controllers="true"secure_all_services="true" />
175+
176+
</srv:container>
177+
178+
.. code-block:: php
179+
180+
// app/config/config.php
181+
$container->loadFromExtension('jms_security_extra', array(
182+
'secure_controllers' => true,
183+
'secure_all_services' => false,
184+
));
185+
186+
To use annotations to secure other services you can set ``secure_all_services``
187+
to true. Alternatively you can specify individual services to secure by tagging
188+
them with ``security.secure_service``:
189+
190+
.. configuration-block::
191+
192+
.. code-block:: yaml
193+
194+
# src/Acme/HelloBundle/Resources/config/services.yml
195+
parameters:
196+
# ...
197+
newsletter_manager.class: Acme\HelloBundle\Newsletter\NewsletterManager
198+
199+
services:
200+
my_mailer:
201+
# ...
202+
newsletter_manager:
203+
class: %newsletter_manager.class%
204+
tags:
205+
- { name: security.secure_service }
206+
207+
.. code-block:: xml
208+
209+
<!-- src/Acme/HelloBundle/Resources/config/services.xml -->
210+
<parameters>
211+
<!-- ... -->
212+
<parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</parameter>
213+
</parameters>
214+
215+
<services>
216+
<service id="my_mailer" ... >
217+
<!-- ... -->
218+
</service>
219+
<service id="newsletter_manager" class="%newsletter_manager.class%">
220+
<tag name="security.secure_service" />
221+
</service>
222+
</services>
223+
224+
.. code-block:: php
225+
226+
// src/Acme/HelloBundle/Resources/config/services.php
227+
use Symfony\Component\DependencyInjection\Definition;
228+
use Symfony\Component\DependencyInjection\Reference;
229+
230+
// ...
231+
$container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager');
232+
233+
$definition = new Definition('%newsletter_manager.class%');
234+
$definition->addTag('security.secure_service');
235+
$container->setDefinition('newsletter_manager', $definition);
236+
237+
You can then achieve the same results as above using an annotation:
238+
239+
.. code-block:: php::
240+
241+
namespace Acme\HelloBundle\Newsletter;
242+
243+
use JMS\SecurityExtraBundle\Annotation\Secure;
244+
// ...
245+
246+
class NewsletterManager
247+
{
248+
249+
/**
250+
* @Secure(roles="ROLE_NEWSLETTER_ADMIN")
251+
*/
252+
public function sendNewsletter()
253+
{
254+
//--
255+
}
256+
257+
// ...
258+
}
259+
260+
.. note::
261+
262+
The annotations work because a proxy class is created for your class
263+
which performs the security checks. This means that, whilst you can use
264+
annotations on public and protected methods, you cannot use them with
265+
private methods or methods marked final.
266+
267+
The ``SecurityExtraBundle`` also allows you to secure the parameters and return
268+
values of methods. For more information, see the `SecurityExtraBundle`_
269+
documentation.
270+
271+
.. _`SecurityExtraBundle`: https://github.com/schmittjoh/SecurityExtraBundle

0 commit comments

Comments
 (0)
0