@@ -22,10 +22,10 @@ for each ``access_control`` entry, which determines whether or not a given
2222access control should be used on this request. The following ``access_control ``
2323options are used for matching:
2424
25- * ``path ``
26- * ``ip `` or ``ips `` ( netmasks are also supported)
27- * ``host ``
28- * ``methods ``
25+ * ``path ``: a regular expression (without delimiters)
26+ * ``ip `` or ``ips ``: netmasks are also supported
27+ * ``host ``: a regular expression
28+ * ``methods ``: one or many methods
2929
3030Take the following ``access_control `` entries as an example:
3131
@@ -37,10 +37,11 @@ Take the following ``access_control`` entries as an example:
3737 security :
3838 # ...
3939 access_control :
40- - { path: ^/admin, roles: ROLE_USER_IP, ip: 127.0.0.1 }
41- - { path: ^/admin, roles: ROLE_USER_HOST, host: symfony\.com$ }
42- - { path: ^/admin, roles: ROLE_USER_METHOD, methods: [POST, PUT] }
43- - { path: ^/admin, roles: ROLE_USER }
40+ - { path: '^/admin', roles: ROLE_USER_IP, ip: 127.0.0.1 }
41+ - { path: '^/admin', roles: ROLE_USER_HOST, host: symfony\.com$ }
42+ - { path: '^/admin', roles: ROLE_USER_METHOD, methods: [POST, PUT] }
43+ # when defining multiple roles, users must have at least one of them (it's like an OR condition)
44+ - { path: '^/admin', roles: [ROLE_MANAGER, ROLE_ADMIN] }
4445
4546 .. code-block :: xml
4647
@@ -57,7 +58,8 @@ Take the following ``access_control`` entries as an example:
5758 <rule path =" ^/admin" role =" ROLE_USER_IP" ip =" 127.0.0.1" />
5859 <rule path =" ^/admin" role =" ROLE_USER_HOST" host =" symfony\.com$" />
5960 <rule path =" ^/admin" role =" ROLE_USER_METHOD" methods =" POST, PUT" />
60- <rule path =" ^/admin" role =" ROLE_USER" />
61+ <!-- when defining multiple roles, users must have at least one of them (it's like an OR condition) -->
62+ <rule path =" ^/admin" roles =" ROLE_ADMIN, ROLE_MANAGER" />
6163 </config >
6264 </srv : container >
6365
@@ -69,31 +71,32 @@ Take the following ``access_control`` entries as an example:
6971 'access_control' => [
7072 [
7173 'path' => '^/admin',
72- 'role ' => 'ROLE_USER_IP',
73- 'ip ' => '127.0.0.1',
74+ 'roles ' => 'ROLE_USER_IP',
75+ 'ips ' => '127.0.0.1',
7476 ],
7577 [
7678 'path' => '^/admin',
77- 'role ' => 'ROLE_USER_HOST',
79+ 'roles ' => 'ROLE_USER_HOST',
7880 'host' => 'symfony\.com$',
7981 ],
8082 [
8183 'path' => '^/admin',
82- 'role ' => 'ROLE_USER_METHOD',
84+ 'roles ' => 'ROLE_USER_METHOD',
8385 'methods' => 'POST, PUT',
8486 ],
8587 [
8688 'path' => '^/admin',
87- 'role' => 'ROLE_USER',
89+ // when defining multiple roles, users must have at least one of them (it's like an OR condition)
90+ 'roles' => ['ROLE_MANAGER', 'ROLE_ADMIN'],
8891 ],
8992 ],
9093 ]);
9194
9295 For each incoming request, Symfony will decide which ``access_control ``
9396to use based on the URI, the client's IP address, the incoming host name,
9497and the request method. Remember, the first rule that matches is used, and
95- if ``ip ``, ``host `` or ``method `` are not specified for an entry, that `` access_control ``
96- will match any ``ip ``, ``host `` or ``method ``:
98+ if ``ips ``, ``host `` or ``methods `` are not specified for an entry, that
99+ `` access_control `` will match any ``ips ``, ``host `` or ``methods ``:
97100
98101+-----------------+-------------+-------------+------------+--------------------------------+-------------------------------------------------------------+
99102| URI | IP | HOST | METHOD | ``access_control `` | Why? |
@@ -114,9 +117,10 @@ will match any ``ip``, ``host`` or ``method``:
114117| ``/admin/user `` | 168.0.0.1 | example.com | POST | rule #3 (``ROLE_USER_METHOD ``) | The ``ip `` and ``host `` don't match the first two entries, |
115118| | | | | | but the third - ``ROLE_USER_METHOD `` - matches and is used. |
116119+-----------------+-------------+-------------+------------+--------------------------------+-------------------------------------------------------------+
117- | ``/admin/user `` | 168.0.0.1 | example.com | GET | rule #4 (``ROLE_USER ``) | The ``ip ``, ``host `` and ``method `` prevent the first |
120+ | ``/admin/user `` | 168.0.0.1 | example.com | GET | rule #4 (``ROLE_MANAGER ``) | The ``ip ``, ``host `` and ``method `` prevent the first |
118121| | | | | | three entries from matching. But since the URI matches the |
119- | | | | | | ``path `` pattern of the ``ROLE_USER `` entry, it is used. |
122+ | | | | | | ``path `` pattern, then the ``ROLE_MANAGER `` (or the |
123+ | | | | | | ``ROLE_ADMIN ``) is used. |
120124+-----------------+-------------+-------------+------------+--------------------------------+-------------------------------------------------------------+
121125| ``/foo `` | 127.0.0.1 | symfony.com | POST | matches no entries | This doesn't match any ``access_control `` rules, since its |
122126| | | | | | URI doesn't match any of the ``path `` values. |
@@ -142,6 +146,14 @@ options:
142146 does not match this value (e.g. ``https ``), the user will be redirected
143147 (e.g. redirected from ``http `` to ``https ``, or vice versa).
144148
149+ .. tip ::
150+
151+ Behind the scenes, the array value of ``roles `` is passed as the
152+ ``$attributes `` argument to each voter in the application with the
153+ :class: `Symfony\\ Component\\ HttpFoundation\\ Request ` as ``$subject ``. You
154+ can learn how to use your custom attributes by reading
155+ :ref: `security/custom-voter `.
156+
145157.. tip ::
146158
147159 If access is denied, the system will try to authenticate the user if not
@@ -178,8 +190,8 @@ pattern so that it is only accessible by requests from the local server itself:
178190 access_control :
179191 #
180192 # the 'ips' option supports IP addresses and subnet masks
181- - { path: ^/internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [127.0.0.1, ::1, 192.168.0.1/24] }
182- - { path: ^/internal, roles: ROLE_NO_ACCESS }
193+ - { path: ' ^/internal' , roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [127.0.0.1, ::1, 192.168.0.1/24] }
194+ - { path: ' ^/internal' , roles: ROLE_NO_ACCESS }
183195
184196 .. code-block :: xml
185197
@@ -212,13 +224,13 @@ pattern so that it is only accessible by requests from the local server itself:
212224 'access_control' => [
213225 [
214226 'path' => '^/internal',
215- 'role ' => 'IS_AUTHENTICATED_ANONYMOUSLY',
227+ 'roles ' => 'IS_AUTHENTICATED_ANONYMOUSLY',
216228 // the 'ips' option supports IP addresses and subnet masks
217229 'ips' => ['127.0.0.1', '::1'],
218230 ],
219231 [
220232 'path' => '^/internal',
221- 'role ' => 'ROLE_NO_ACCESS',
233+ 'roles ' => 'ROLE_NO_ACCESS',
222234 ],
223235 ],
224236 ]);
@@ -263,7 +275,10 @@ key:
263275 access_control :
264276 -
265277 path : ^/_internal/secure
266- allow_if : " '127.0.0.1' == request.getClientIp() or has_role('ROLE_ADMIN')"
278+ # the 'role' and 'allow-if' options work like an OR expression, so
279+ # access is granted if the expression is TRUE or the user has ROLE_ADMIN
280+ roles : ' ROLE_ADMIN'
281+ allow_if : " '127.0.0.1' == request.getClientIp() or request.header.has('X-Secure-Access')"
267282
268283 .. code-block :: xml
269284
@@ -276,8 +291,11 @@ key:
276291 https://symfony.com/schema/dic/services/services-1.0.xsd" >
277292
278293 <config >
294+ <!-- the 'role' and 'allow-if' options work like an OR expression, so
295+ access is granted if the expression is TRUE or the user has ROLE_ADMIN -->
279296 <rule path =" ^/_internal/secure"
280- allow-if =" '127.0.0.1' == request.getClientIp() or has_role('ROLE_ADMIN')" />
297+ role =" ROLE_ADMIN"
298+ allow-if =" '127.0.0.1' == request.getClientIp() or request.header.has('X-Secure-Access')" />
281299 </config >
282300 </srv : container >
283301
@@ -286,13 +304,22 @@ key:
286304 'access_control' => [
287305 [
288306 'path' => '^/_internal/secure',
289- 'allow_if' => '"127.0.0.1" == request.getClientIp() or has_role("ROLE_ADMIN")',
307+ // the 'role' and 'allow-if' options work like an OR expression, so
308+ // access is granted if the expression is TRUE or the user has ROLE_ADMIN
309+ 'roles' => 'ROLE_ADMIN',
310+ 'allow_if' => '"127.0.0.1" == request.getClientIp() or request.header.has('X-Secure-Access')',
290311 ],
291312 ],
292313
293- In this case, when the user tries to access any URL starting with ``/_internal/secure ``,
294- they will only be granted access if the IP address is ``127.0.0.1 `` or if
295- the user has the ``ROLE_ADMIN `` role.
314+ In this case, when the user tries to access any URL starting with
315+ ``/_internal/secure ``, they will only be granted access if the IP address is
316+ ``127.0.0.1 `` or a secure header, or if the user has the ``ROLE_ADMIN `` role.
317+
318+ .. note ::
319+
320+ Internally ``allow_if `` triggers the built-in
321+ :class: `Symfony\\ Component\\ Security\\ Core\\ Authorization\\ Voter\\ ExpressionVoter `
322+ as like it was part of the attributes defined in the ``roles `` option.
296323
297324Inside the expression, you have access to a number of different variables
298325and functions including ``request ``, which is the Symfony
@@ -343,7 +370,7 @@ the user will be redirected to ``https``:
343370 'access_control' => [
344371 [
345372 'path' => '^/cart/checkout',
346- 'role ' => 'IS_AUTHENTICATED_ANONYMOUSLY',
373+ 'roles ' => 'IS_AUTHENTICATED_ANONYMOUSLY',
347374 'requires_channel' => 'https',
348375 ],
349376 ],
0 commit comments