1
1
How to secure any Service or Method in your Application
2
2
=======================================================
3
3
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
4
+ In the security chapter, you can see how to :ref: `secure a controller<book-security-securing-controller> `
5
+ by requesting the ``security.context `` service from the Service Container
6
+ and checking the current user's role::
9
7
10
8
use Symfony\Component\Security\Core\Exception\AccessDeniedException
11
9
// ...
@@ -19,12 +17,12 @@ from the Service Container and checking the current user's role:
19
17
// ...
20
18
}
21
19
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:
20
+ You can also secure * any * service in a similar way by injecting the `` security.context ``
21
+ service into it. For a general introduction to injecting dependencies into
22
+ services see the :doc: `/book/service_container ` chapter of the book. For
23
+ example, suppose you have a ``NewsletterManager `` class that sends out emails
24
+ and you want to restrict its use to only users who have some `` ROLE_NEWSLETTER_ADMIN ``
25
+ role. Before you add security, the class looks something like this:
28
26
29
27
.. code-block :: php
30
28
@@ -35,47 +33,46 @@ newsletters and want to restrict its use to only users with the
35
33
36
34
public function sendNewsletter()
37
35
{
38
- //--
36
+ // where you actually do the work
39
37
}
40
38
41
39
// ...
42
40
}
43
41
44
- You want to check the user's role when the ``sendNewsletter() `` method is
42
+ Your goal is to check the user's role when the ``sendNewsletter() `` method is
45
43
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
44
+ service into the object. Since it won't make sense * not * to perform the security
45
+ check, this is an ideal candidate for constructor injection, which guarantees
46
+ that the security context object will be available inside the `` NewsletterManager ``
47
+ class::
50
48
51
49
namespace Acme\HelloBundle\Newsletter;
50
+
51
+ use Symfony\Component\Security\Core\SecurityContextInterface;
52
52
53
53
class NewsletterManager
54
54
{
55
55
protected $securityContext;
56
56
57
- public function __construct($securityContext)
57
+ public function __construct(SecurityContextInterface $securityContext)
58
58
{
59
59
$this->securityContext = $securityContext;
60
60
}
61
61
62
62
// ...
63
63
}
64
64
65
- Then in your config you can inject the service:
65
+ Then in your service configuration, you can inject the service:
66
66
67
67
.. configuration-block ::
68
68
69
69
.. code-block :: yaml
70
70
71
71
# src/Acme/HelloBundle/Resources/config/services.yml
72
72
parameters :
73
- # ...
74
73
newsletter_manager.class : Acme\HelloBundle\Newsletter\NewsletterManager
75
74
76
75
services :
77
- my_mailer :
78
- # ...
79
76
newsletter_manager :
80
77
class : %newsletter_manager.class%
81
78
arguments : [@security.context]
@@ -84,14 +81,10 @@ Then in your config you can inject the service:
84
81
85
82
<!-- src/Acme/HelloBundle/Resources/config/services.xml -->
86
83
<parameters >
87
- <!-- ... -->
88
84
<parameter key =" newsletter_manager.class" >Acme\HelloBundle\Newsletter\NewsletterManager</parameter >
89
85
</parameters >
90
86
91
87
<services >
92
- <service id =" my_mailer" ... >
93
- <!-- ... -->
94
- </service >
95
88
<service id =" newsletter_manager" class =" %newsletter_manager.class%" >
96
89
<argument type =" service" id =" security.context" />
97
90
</service >
@@ -103,7 +96,6 @@ Then in your config you can inject the service:
103
96
use Symfony\Component\DependencyInjection\Definition;
104
97
use Symfony\Component\DependencyInjection\Reference;
105
98
106
- // ...
107
99
$container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager');
108
100
109
101
$container->setDefinition('newsletter_manager', new Definition(
@@ -112,21 +104,19 @@ Then in your config you can inject the service:
112
104
));
113
105
114
106
The injected service can then be used to perform the security check when the
115
- ``sendNewsletter() `` method is called:
116
-
117
- .. code-block :: php::
107
+ ``sendNewsletter() `` method is called::
118
108
119
109
namespace Acme\HelloBundle\Newsletter;
120
110
121
111
use Symfony\Component\Security\Core\Exception\AccessDeniedException
122
- use Symfony\C omponent\S ecurity\C ore\S ecurityContext ;
112
+ use Symfony\Component\Security\Core\SecurityContextInterface ;
123
113
// ...
124
114
125
115
class NewsletterManager
126
116
{
127
117
protected $securityContext;
128
118
129
- public function __construct(SecurityContext $securityContext)
119
+ public function __construct(SecurityContextInterface $securityContext)
130
120
{
131
121
$this->securityContext = $securityContext;
132
122
}
@@ -143,80 +133,42 @@ The injected service can then be used to perform the security check when the
143
133
// ...
144
134
}
145
135
146
- If the current user does not have the ``ROLE_NEWSLETTER_ADMIN `` then they
147
- will be prompted to log in.
136
+ If the current user does not have the ``ROLE_NEWSLETTER_ADMIN ``, they will
137
+ be prompted to log in.
148
138
149
139
Securing Methods Using Annotations
150
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
140
+ ----------------------------------
151
141
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:
142
+ You can also secure method calls in any service with annotations by using the
143
+ optional `SecurityExtraBundle `_ bundle. This bundle is included in the Symfony2
144
+ Standard Distribution.
156
145
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 ``:
146
+ To enable the annotations functionality, :ref: `tag<book-service-container-tags> `
147
+ the service you want to secure with the ``security.secure_service `` tag
148
+ (you can also automatically enable this functionality for all services, see
149
+ the :ref: `sidebar<securing-services-annotations-sidebar> ` below):
189
150
190
151
.. configuration-block ::
191
152
192
153
.. code-block :: yaml
193
154
194
155
# src/Acme/HelloBundle/Resources/config/services.yml
195
- parameters :
196
- # ...
197
- newsletter_manager.class : Acme\HelloBundle\Newsletter\NewsletterManager
156
+ # ...
198
157
199
158
services :
200
- my_mailer :
201
- # ...
202
159
newsletter_manager :
203
- class : %newsletter_manager.class%
160
+ # ...
204
161
tags :
205
162
- { name: security.secure_service }
206
163
207
164
.. code-block :: xml
208
165
209
166
<!-- src/Acme/HelloBundle/Resources/config/services.xml -->
210
- <parameters >
211
- <!-- ... -->
212
- <parameter key =" newsletter_manager.class" >Acme\HelloBundle\Newsletter\NewsletterManager</parameter >
213
- </parameters >
167
+ <!-- ... -->
214
168
215
169
<services >
216
- <service id =" my_mailer" ... >
217
- <!-- ... -->
218
- </service >
219
170
<service id =" newsletter_manager" class =" %newsletter_manager.class%" >
171
+ <!-- ... -->
220
172
<tag name =" security.secure_service" />
221
173
</service >
222
174
</services >
@@ -227,16 +179,14 @@ them with ``security.secure_service``:
227
179
use Symfony\Component\DependencyInjection\Definition;
228
180
use Symfony\Component\DependencyInjection\Reference;
229
181
230
- // ...
231
- $container->setParameter(' newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager');
232
-
233
- $definition = new Definition('%newsletter_manager.class%' );
182
+ $definition = new Definition(
183
+ '% newsletter_manager.class%',
184
+ array(new Reference('security.context'))
185
+ ) );
234
186
$definition->addTag('security.secure_service');
235
187
$container->setDefinition('newsletter_manager', $definition);
236
188
237
- You can then achieve the same results as above using an annotation:
238
-
239
- .. code-block :: php::
189
+ You can then achieve the same results as above using an annotation::
240
190
241
191
namespace Acme\HelloBundle\Newsletter;
242
192
@@ -268,4 +218,45 @@ The ``SecurityExtraBundle`` also allows you to secure the parameters and return
268
218
values of methods. For more information, see the `SecurityExtraBundle `_
269
219
documentation.
270
220
221
+ .. _securing-services-annotations-sidebar :
222
+
223
+ .. sidebar :: Activating the Annotations Functionality for all Services
224
+
225
+ When securing the method of a service (as shown above), you can either
226
+ tag each service individually, or activate the functionality for *all *
227
+ services at once. To do so, set the ``secure_all_services `` configuration
228
+ option to true:
229
+
230
+ .. configuration-block ::
231
+
232
+ .. code-block :: yaml
233
+
234
+ # app/config/config.yml
235
+ jms_security_extra :
236
+ # ...
237
+ secure_all_services : false
238
+
239
+ .. code-block :: xml
240
+
241
+ <!-- app/config/config.xml -->
242
+ <srv : container xmlns =" http://symfony.com/schema/dic/security"
243
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
244
+ xmlns : srv =" http://symfony.com/schema/dic/services"
245
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" >
246
+
247
+ <jms_security_extra secure_controllers =" true" secure_all_services =" true" />
248
+
249
+ </srv : container >
250
+
251
+ .. code-block :: php
252
+
253
+ // app/config/config.php
254
+ $container->loadFromExtension('jms_security_extra', array(
255
+ // ...
256
+ 'secure_all_services' => false,
257
+ ));
258
+
259
+ The disadvantage of this method is that, if activated, the initial page
260
+ load may be very slow depending on how many services you have defined.
261
+
271
262
.. _`SecurityExtraBundle` : https://github.com/schmittjoh/SecurityExtraBundle
0 commit comments