11.. index ::
22 single: Security; Data Permission Voters
33
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+ ===========================================
66
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
88:doc: `ACL module </cookbook/security/acl >`, which is a bit overwhelming
99for many applications. A much easier solution is to work with custom voters,
1010which are like simple conditional statements. Voters can be
1111also 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 `" .
1313
1414.. tip ::
1515
16- Have a look at the pages
17- :doc: `security </cookbook/security >` and
16+ Have a look at the chapter
1817 :doc: `authorization </components/security/authorization >`
19- if you are not familiar with these topics .
18+ for a better understanding on voters .
2019
21- How Symfony uses Voters
20+ How Symfony Uses Voters
2221-----------------------
2322
2423In order to use voters, you have to understand how Symfony works with them.
2524In general, all registered custom voters will be called every time you ask
2625Symfony about permissions (ACL). You can use one of three different
2726approaches on how to handle the feedback from all voters: affirmative,
2827consensus and unanimous. For more information have a look at
29- :ref: `" components-security-access-decision-manager" ` .
28+ " :ref: `components-security-access-decision-manager `" .
3029
3130The Voter Interface
3231-------------------
@@ -35,30 +34,7 @@ A custom voter must implement
3534:class: `Symfony\\ Component\\ Security\\ Core\\ Authorization\\ Voter\\ VoterInterface `,
3635which has this structure:
3736
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
6238
6339In this example, you'll check if the user will have access to a specific
6440object 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``
7046Creating the Custom Voter
7147-------------------------
7248
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::
7650
7751 // src/Acme/DemoBundle/Security/Authorization/Entity/PostVoter.php
7852 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
10074
10175 foreach ($array as $item) {
10276 if ($obj instanceof $item))
103-
10477 return true;
10578 }
10679 }
@@ -113,7 +86,9 @@ You could store your Voter to check permission for the view and edit action like
11386 {
11487 // check if voter is used correct, only allow one attribute for a check
11588 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+ );
11792 }
11893
11994 // 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
12398 $user = $token->getUser();
12499
125100 // check if class of this object is supported by this voter
126- if (!($this->supportsClass($post))) {
127-
101+ if (!$this->supportsClass($post)) {
128102 return VoterInterface::ACCESS_ABSTAIN;
129103 }
130104
131105 // check if the given attribute is covered by this voter
132106 if (!$this->supportsAttribute($attribute)) {
133-
134107 return VoterInterface::ACCESS_ABSTAIN;
135108 }
136109
137110 // check if given user is instance of user interface
138- if (!($user instanceof UserInterface)) {
139-
111+ if (!$user instanceof UserInterface) {
140112 return VoterInterface::ACCESS_DENIED;
141113 }
142114
143115 switch($attribute) {
144116 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
146119 if (!$post->isPrivate()) {
147-
148120 return VoterInterface::ACCESS_GRANTED;
149121 }
150122 break;
151123
152124 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
154127 if ($user->getId() === $post->getOwner()->getId()) {
155-
156128 return VoterInterface::ACCESS_GRANTED;
157129 }
158130 break;
159131
160132 default:
161133 // 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+ );
163137 }
164138
165139 }
@@ -171,8 +145,8 @@ the security layer. This can be done easily through the service container.
171145Declaring the Voter as a Service
172146--------------------------------
173147
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´ :
176150
177151.. configuration-block ::
178152
@@ -202,12 +176,17 @@ and tag it as a "security.voter":
202176 .. code-block :: php
203177
204178 $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+ )
206183 ->addTag('security.voter')
207184 ;
208185
209- How to use the Voter in a Controller
186+ How to Use the Voter in a Controller
210187------------------------------------
188+ The registered voter will then always be asked as soon the method isGranted from
189+ the security context is called.
211190
212191.. code-block :: php
213192
@@ -222,14 +201,14 @@ How to use the Voter in a Controller
222201 public function showAction($id)
223202 {
224203 // 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 )) {
226205 throw new AccessDeniedException('Unauthorised access!');
227206 }
228207
229208 $product = $this->getDoctrine()
230209 ->getRepository('AcmeStoreBundle:Post')
231210 ->find($id);
232211
233- return new Response('<html >< body >Headline for Post: '.$post->getName().'</body ></ html >');
212+ return new Response('<h1 > '.$post->getName().'</h1 >');
234213 }
235214 }
0 commit comments