Skip to content

Commit ee44fe4

Browse files
committed
Reverts a commit to 2.3 for 2.4 features. This re-adds them to the 2.5 branch
Revert "Remove ExpressionLanguage reference for 2.3 version" This reverts commit d1e7334. Conflicts: best_practices/security.rst
1 parent 646d933 commit ee44fe4

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

best_practices/security.rst

+87
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,91 @@ Using ``@Security``, this looks like:
123123
// ...
124124
}
125125
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+
126211
Checking Permissions without @Security
127212
--------------------------------------
128213

@@ -267,7 +352,9 @@ develop :doc:`your own user provider </cookbook/security/custom_provider>` and
267352

268353
.. _`Security Cookbook Section`: http://symfony.com/doc/current/cookbook/security/index.html
269354
.. _`security.yml`: http://symfony.com/doc/current/reference/configuration/security.html
355+
.. _`ParamConverter`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
270356
.. _`@Security annotation`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html
271357
.. _`security voter`: http://symfony.com/doc/current/cookbook/security/voters_data_permission.html
272358
.. _`ACL's`: http://symfony.com/doc/current/cookbook/security/acl.html
359+
.. _`expression`: http://symfony.com/doc/current/components/expression_language/introduction.html
273360
.. _`FOSUserBundle`: https://github.com./FriendsOfSymfony/FOSUserBundle

0 commit comments

Comments
 (0)