Symfony2 fosUserBundle vs KNPMenuBundle
Ik gebruik in Symfony de fosUserBundle en de KNPMenuBundle.
De fosUserBundle zorgt voor een compleet inlogsysteem compleet met userroles.
In de app/security.yml staat de access control:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/user/, role: ROLE_BOARDMEMBER }
- { path: ^/admin/members/, role: ROLE_BOARDMEMBER }
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/user/, role: ROLE_BOARDMEMBER }
- { path: ^/admin/members/, role: ROLE_BOARDMEMBER }
- { path: ^/admin/, role: ROLE_ADMIN }
Als voorbeeld neem ik even de laatste regel. De gebruiker moet de ROLE_ADMIN rol hebben om de ROUTE /admin/ te kunnen raadplegen. Dit werkt allemaal prima.
Echter Wil ik mijn CSS menu welke met behulp van KNPMenuBundle vervaardigd wordt dynamisch maken.
Ik wil dus dat de menuitem/link naar de adminpagina alleen gemaakt wordt als de ingelogde gebruiker daar ook op mag komen.
Nu weet ik wel dat je van de ingelogde gebruiker zijn rollen kunt opvragen. (je krijgt dan bijvoorbeeld een array('ROLE_USER', 'ROLE_ADMIN') terug maar ik wil liever aan de hand van de ROUTES bepalen of een gebruiker dan wel of geen toestemming heeft om daar heen te gaan.
anders gezegd:
als ik weet dat de router-identifier 'admin_homepage' is
hoe kan ik dan de roles opvragen uit de access control voor het pad ^/admin/
Waarom ik dit wil is vrij simpel. Stel dat ik nu later een andere rol aan een pad in de access control wil koppelen dan past mijn menu zich automatisch aan.
Waarschijnlijk denk ik niet in de goede richting maar goed ik hoor graag van de Symfony gebruikers
Gewijzigd op 26/05/2014 23:15:06 door Frank Nietbelangrijk
Geen oplossing maar ik weet wel dat het authenticatie systeem van Symfony echt een bitch is :D Succes ermee! Mocht je er helemaal niet uit komen kun je het altijd even @freenode chat vragen, die hebben mij de vorige keer ook geholpen
Merk overigens op dat de FOSUserBundle hier niks mee te maken heeft, het betreft hier alleen de SecurityBundle/Security component geleverd door Symfony.
Wat je hierbij nodig hebt:
- Symfony\Component\Security\Http\AccessMap - Hiermee kun je de vereiste roles opvragen aan de hand van een request
- Symfony\Component\HttpFoundation\Request - Om zo'n request te simuleren
- Symfony\Component\Routing\Router - Om de path te genereren van een route
- Symfony\Component\Security\Core\Authorization\AccessDecisionManager - Om te kijken of de benodigde roles aanwezig zijn
- Symfony\Component\Security\Core\SecurityContext - Om de huidige tokens op te vragen
Aan het eind wil je iets als de AccessListener gaan maken, dus:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
use Symfony\Component\HttpFoundation\Request;
// deze inject je
$router = ...; // router
$accessMap = ...; // security.access_map
$accessDecisionManager = ...; // security.access.decision_manager
$context = ...; // security.context
// verkrijg de url doormiddel van de route naam
$route = 'admin_homepage';
$url = $router->generate($route);
// simuleer een request naar deze url
$request = Request::create($url);
// verkrijg de benodigde attributes (roles) voor deze request (channel is https/http)
list($attributes, $channel) = $accessMap->getPatterns($request);
// verkrijg de huidige token
$token = $context->getToken();
if (
// geen attributes nodig? Mooi, dan mag de user hem zien!
null === $attributes
// als er wel attributes nodig zijn, heb ik de benodigde attributes?
|| $accessDecisionManager->decide($token, $attributes, $request)
) {
// toon menu item
}
?>
use Symfony\Component\HttpFoundation\Request;
// deze inject je
$router = ...; // router
$accessMap = ...; // security.access_map
$accessDecisionManager = ...; // security.access.decision_manager
$context = ...; // security.context
// verkrijg de url doormiddel van de route naam
$route = 'admin_homepage';
$url = $router->generate($route);
// simuleer een request naar deze url
$request = Request::create($url);
// verkrijg de benodigde attributes (roles) voor deze request (channel is https/http)
list($attributes, $channel) = $accessMap->getPatterns($request);
// verkrijg de huidige token
$token = $context->getToken();
if (
// geen attributes nodig? Mooi, dan mag de user hem zien!
null === $attributes
// als er wel attributes nodig zijn, heb ik de benodigde attributes?
|| $accessDecisionManager->decide($token, $attributes, $request)
) {
// toon menu item
}
?>
Deze code kun je in je MenuBuilder plaatsen, maar vanaf KnpMenuBundle 2.0 (welke nu in beta is dacht ik) kun je dit in een voter plaatsen. Wil je dat nu al gebruiken, dan verwijs ik graat naar de CMF MenuBundle die gebouwd is op de KnpMenuBundle en onder andere voters implementeert.
Ik ga kijken of ik er mee vooruit kom en ik hou jullie op de hoogte.