@@ -123,6 +123,91 @@ Using ``@Security``, this looks like:
123
123
// ...
124
124
}
125
125
126
+ Using Expressions for Complex Security Restrictions
127
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
128
+
129
+ If your security logic is a little bit more complex, you can use an `expression `_
130
+ inside ``@Security ``. In the following example, a user can only access the
131
+ controller if their email matches the value returned by the ``getAuthorEmail ``
132
+ method on the ``Post `` object:
133
+
134
+ .. code-block :: php
135
+
136
+ use AppBundle\Entity\Post;
137
+ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
138
+ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
139
+
140
+ /**
141
+ * @Route("/{id}/edit", name="admin_post_edit")
142
+ * @Security("user.getEmail() == post.getAuthorEmail()")
143
+ */
144
+ public function editAction(Post $post)
145
+ {
146
+ // ...
147
+ }
148
+
149
+ Notice that this requires the use of the `ParamConverter `_, which automatically
150
+ queries for the ``Post `` object and puts it on the ``$post `` argument. This
151
+ is what makes it possible to use the ``post `` variable in the expression.
152
+
153
+ This has one major drawback: an expression in an annotation cannot easily
154
+ be reused in other parts of the application. Imagine that you want to add
155
+ a link in a template that will only be seen by authors. Right now you'll
156
+ need to repeat the expression code using Twig syntax:
157
+
158
+ .. code-block :: html+jinja
159
+
160
+ {% if app.user and app.user.email == post.authorEmail %}
161
+ <a href=""> ... </a>
162
+ {% endif %}
163
+
164
+ The easiest solution - if your logic is simple enough - is to add a new method
165
+ to the ``Post `` entity that checks if a given user is its author:
166
+
167
+ .. code-block :: php
168
+
169
+ // src/AppBundle/Entity/Post.php
170
+ // ...
171
+
172
+ class Post
173
+ {
174
+ // ...
175
+
176
+ /**
177
+ * Is the given User the author of this Post?
178
+ *
179
+ * @return bool
180
+ */
181
+ public function isAuthor(User $user = null)
182
+ {
183
+ return $user && $user->getEmail() == $this->getAuthorEmail();
184
+ }
185
+ }
186
+
187
+ Now you can reuse this method both in the template and in the security expression:
188
+
189
+ .. code-block :: php
190
+
191
+ use AppBundle\Entity\Post;
192
+ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
193
+
194
+ /**
195
+ * @Route("/{id}/edit", name="admin_post_edit")
196
+ * @Security("post.isAuthor(user)")
197
+ */
198
+ public function editAction(Post $post)
199
+ {
200
+ // ...
201
+ }
202
+
203
+ .. code-block :: html+jinja
204
+
205
+ {% if post.isAuthor(app.user) %}
206
+ <a href=""> ... </a>
207
+ {% endif %}
208
+
209
+ .. _best-practices-directly-isGranted :
210
+
126
211
Checking Permissions without @Security
127
212
--------------------------------------
128
213
@@ -267,7 +352,9 @@ develop :doc:`your own user provider </cookbook/security/custom_provider>` and
267
352
268
353
.. _`Security Cookbook Section` : http://symfony.com/doc/current/cookbook/security/index.html
269
354
.. _`security.yml` : http://symfony.com/doc/current/reference/configuration/security.html
355
+ .. _`ParamConverter` : http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
270
356
.. _`@Security annotation` : http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html
271
357
.. _`security voter` : http://symfony.com/doc/current/cookbook/security/voters_data_permission.html
272
358
.. _`ACL's` : http://symfony.com/doc/current/cookbook/security/acl.html
359
+ .. _`expression` : http://symfony.com/doc/current/components/expression_language/introduction.html
273
360
.. _`FOSUserBundle` : https://github.com./FriendsOfSymfony/FOSUserBundle
0 commit comments