1
1
.. index ::
2
2
single: Security; Data Permission Voters
3
3
4
- How to implement your own Voter to check User Permissions for accessing a Given Object
5
- ======================================================================================
4
+ How to Use Voters to Check User Permissions
5
+ ===========================================
6
6
7
- In Symfony2 you can check the permission to access data by the
7
+ In Symfony2 you can check the permission to access data by using the
8
8
:doc: `ACL module </cookbook/security/acl >`, which is a bit overwhelming
9
9
for many applications. A much easier solution is to work with custom voters,
10
10
which are like simple conditional statements. Voters can be
11
11
also be used to check for permission as a part or even the whole
12
- application: :doc: `" /cookbook/security/voters" ` .
12
+ application: " :doc: `/cookbook/security/voters `" .
13
13
14
14
.. tip ::
15
15
16
- Have a look at the pages
17
- :doc: `security </cookbook/security >` and
16
+ Have a look at the chapter
18
17
:doc: `authorization </components/security/authorization >`
19
- if you are not familiar with these topics .
18
+ for a better understanding on voters .
20
19
21
- How Symfony uses Voters
20
+ How Symfony Uses Voters
22
21
-----------------------
23
22
24
23
In order to use voters, you have to understand how Symfony works with them.
25
24
In general, all registered custom voters will be called every time you ask
26
25
Symfony about permissions (ACL). You can use one of three different
27
26
approaches on how to handle the feedback from all voters: affirmative,
28
27
consensus and unanimous. For more information have a look at
29
- :ref: `" components-security-access-decision-manager" ` .
28
+ " :ref: `components-security-access-decision-manager `" .
30
29
31
30
The Voter Interface
32
31
-------------------
@@ -35,30 +34,7 @@ A custom voter must implement
35
34
:class: `Symfony\\ Component\\ Security\\ Core\\ Authorization\\ Voter\\ VoterInterface `,
36
35
which has this structure:
37
36
38
- // how to put this following snippet (to line 56) in a single file an embed it? as it is used in voters.rst as well.
39
-
40
- .. code-block :: php
41
-
42
- interface VoterInterface
43
- {
44
- public function supportsAttribute($attribute);
45
- public function supportsClass($class);
46
- public function vote(TokenInterface $token, $post, array $attributes);
47
- }
48
-
49
- The ``supportsAttribute() `` method is used to check if the voter supports
50
- the given user attribute (i.e: a role, an acl, etc.).
51
-
52
- The ``supportsClass() `` method is used to check if the voter supports the
53
- current user token class.
54
-
55
- The ``vote() `` method must implement the business logic that verifies whether
56
- or not the user is granted access. This method must return one of the following
57
- values:
58
-
59
- * ``VoterInterface::ACCESS_GRANTED ``: The user is allowed to access the application
60
- * ``VoterInterface::ACCESS_ABSTAIN ``: The voter cannot decide if the user is granted or not
61
- * ``VoterInterface::ACCESS_DENIED ``: The user is not allowed to access the application
37
+ .. include :: /cookbook/security/voter_interface.rst.inc
62
38
63
39
In this example, you'll check if the user will have access to a specific
64
40
object according to your custom conditions (e.g. he must be the owner of
@@ -70,9 +46,7 @@ does not belong to this voter, it will return ``VoterInterface::ACCESS_ABSTAIN``
70
46
Creating the Custom Voter
71
47
-------------------------
72
48
73
- You could store your Voter to check permission for the view and edit action like following.
74
-
75
- .. code-block :: php
49
+ You could store your Voter to check permission for the view and edit action like the following::
76
50
77
51
// src/Acme/DemoBundle/Security/Authorization/Entity/PostVoter.php
78
52
namespace Acme\DemoBundle\Security\Authorization\Entity;
@@ -100,7 +74,6 @@ You could store your Voter to check permission for the view and edit action like
100
74
101
75
foreach ($array as $item) {
102
76
if ($obj instanceof $item))
103
-
104
77
return true;
105
78
}
106
79
}
@@ -113,7 +86,9 @@ You could store your Voter to check permission for the view and edit action like
113
86
{
114
87
// check if voter is used correct, only allow one attribute for a check
115
88
if(count($attributes) !== 1 || !is_string($attributes[0])) {
116
- throw new PreconditionFailedHttpException('The Attribute was not set correct. Maximum 1 attribute.');
89
+ throw new PreconditionFailedHttpException(
90
+ 'Only one attribute is allowed for VIEW or EDIT'
91
+ );
117
92
}
118
93
119
94
// set the attribute to check against
@@ -123,43 +98,42 @@ You could store your Voter to check permission for the view and edit action like
123
98
$user = $token->getUser();
124
99
125
100
// check if class of this object is supported by this voter
126
- if (!($this->supportsClass($post))) {
127
-
101
+ if (!$this->supportsClass($post)) {
128
102
return VoterInterface::ACCESS_ABSTAIN;
129
103
}
130
104
131
105
// check if the given attribute is covered by this voter
132
106
if (!$this->supportsAttribute($attribute)) {
133
-
134
107
return VoterInterface::ACCESS_ABSTAIN;
135
108
}
136
109
137
110
// check if given user is instance of user interface
138
- if (!($user instanceof UserInterface)) {
139
-
111
+ if (!$user instanceof UserInterface) {
140
112
return VoterInterface::ACCESS_DENIED;
141
113
}
142
114
143
115
switch($attribute) {
144
116
case 'view':
145
- // the data object could have for e.g. a method isPrivate() which checks the the boolean attribute $private
117
+ // the data object could have for e.g. a method isPrivate()
118
+ // which checks the Boolean attribute $private
146
119
if (!$post->isPrivate()) {
147
-
148
120
return VoterInterface::ACCESS_GRANTED;
149
121
}
150
122
break;
151
123
152
124
case 'edit':
153
- // we assume that our data object has a method getOwner() to get the current owner user entity for this data object
125
+ // we assume that our data object has a method getOwner() to
126
+ // get the current owner user entity for this data object
154
127
if ($user->getId() === $post->getOwner()->getId()) {
155
-
156
128
return VoterInterface::ACCESS_GRANTED;
157
129
}
158
130
break;
159
131
160
132
default:
161
133
// otherwise throw an exception, which will break the request
162
- throw new PreconditionFailedHttpException('The Attribute "'.$attribute.'" was not found.')
134
+ throw new PreconditionFailedHttpException(
135
+ 'The Attribute "'.$attribute.'" was not found.'
136
+ );
163
137
}
164
138
165
139
}
@@ -171,8 +145,8 @@ the security layer. This can be done easily through the service container.
171
145
Declaring the Voter as a Service
172
146
--------------------------------
173
147
174
- To inject the voter into the security layer, you must declare it as a service,
175
- and tag it as a " security.voter" :
148
+ To inject the voter into the security layer, you must declare it as a service
149
+ and tag it as a ´ security.voter´ :
176
150
177
151
.. configuration-block ::
178
152
@@ -202,12 +176,17 @@ and tag it as a "security.voter":
202
176
.. code-block :: php
203
177
204
178
$container
205
- ->register('security.access.post_document_voter', 'Acme\DemoBundle\Security\Authorization\Document\PostVoter')
179
+ ->register(
180
+ 'security.access.post_document_voter',
181
+ 'Acme\DemoBundle\Security\Authorization\Document\PostVoter'
182
+ )
206
183
->addTag('security.voter')
207
184
;
208
185
209
- How to use the Voter in a Controller
186
+ How to Use the Voter in a Controller
210
187
------------------------------------
188
+ The registered voter will then always be asked as soon the method isGranted from
189
+ the security context is called.
211
190
212
191
.. code-block :: php
213
192
@@ -222,14 +201,14 @@ How to use the Voter in a Controller
222
201
public function showAction($id)
223
202
{
224
203
// keep in mind, this will call all registered security voters
225
- if (false === $this->get('security.context')->isGranted('view')) {
204
+ if (false === $this->get('security.context')->isGranted('view', $post )) {
226
205
throw new AccessDeniedException('Unauthorised access!');
227
206
}
228
207
229
208
$product = $this->getDoctrine()
230
209
->getRepository('AcmeStoreBundle:Post')
231
210
->find($id);
232
211
233
- return new Response('<html >< body >Headline for Post: '.$post->getName().'</body ></ html >');
212
+ return new Response('<h1 > '.$post->getName().'</h1 >');
234
213
}
235
214
}
0 commit comments