Reputation: 1120
How can I check user role in code of a symfony2 Service? Should I simply send a user roles object to a Service or is there solution which allows me to do the check from Service level?
Upvotes: 4
Views: 8896
Reputation: 4265
Assuming that:
you inject security.context
in your service
public function __construct(SecurityContext $securityContext) {
$this->securityContext = $securityContext;
}
you are using FosUserBundle
I understood correctly your question :-)
you should be able to do:
$token = $this->securityContext->getToken();
if (empty($token)) {
return [];
}
$user = $token->getUser();
if (empty($user)) {
return [];
}
$roles = $user->getRoles();
Upvotes: 2
Reputation: 31919
Be very careful about what you are doing when it comes to Security.. DO NOT DO THIS.
This is because, you need to understand that the TokenInterface is not the same as UserInterface
.
TokenInterface is the interface for the user authentication information.
You must use it - If you don't have the token made available in your current service, use the SecurityContext
or the AccessDecisionManager
.
Note: In Symfony > 2.6, some improvements were made, and SecurityContext
was deprecated, and split into TokenStorage
and AuthorizationChecker
. So, you can go ahead and use AuthorizationChecker
now.
Look! Even FOSUserBundle implementation talks about it:
/**
* Never use this to check if this user has access to anything!
*
* Use the SecurityContext, or an implementation of AccessDecisionManager
* instead, e.g.
*
* $securityContext->isGranted('ROLE_USER');
*
* @param string $role
* @return Boolean
*/
function hasRole($role);
Look how it works, look at things like getRoles, Hierarchical roles for example.
ROLES in the database are not to be trusted - if you get a User object from the database, and use your getRoles()
or even worse the special isGranted($role)
you have created, they will NOT have the roles you expect your user to have.
This should be your bible, and now you can understand the differences between:
1 $user->getRoles()
array(2) {
[0]=> string(10) "ROLE_ADMIN"
[1]=> string(9) "ROLE_USER"
}
2 $this->token->getRoles()
array(2) {
[0]=> object(Symfony\Component\Security\Core\Role\Role)
(1) { ["role":"Symfony\Component\Security\Core\Role\Role":private]=> string(10) "ROLE_ADMIN" }
[1]=> object(Symfony\Component\Security\Core\Role\Role)
(1) { ["role":"Symfony\Component\Security\Core\Role\Role":private]=> string(22) "ROLE_ALLOWED_TO_SWITCH" }
[2]=> object(Symfony\Component\Security\Core\Role\Role)
(1) { ["role":"Symfony\Component\Security\Core\Role\Role":private]=> string(9) "ROLE_USER" }
}
3 $this->token->getUser->getRoles()
array(2) {
[0]=> string(10) "ROLE_ADMIN"
[1]=> string(22) "ROLE_ALLOWED_TO_SWITCH"
[2]=> string(9) "ROLE_USER"
}
When you have security.yml
security:
role_hierarchy:
ROLE_ADMIN: [ROLE_ALLOWED_TO_SWITCH]
Upvotes: 0
Reputation: 1300
See here for more info.
I think it would be much easier if you implemented an isGranted function in the User entity:
Class User implements UserInterface {
...
public function isGranted($role)
{
return in_array($role, $this->getRoles());
}
}
You can now easily check for granted roles in every layer of your application. In PHP:
$user->isGranted("USER_ADMIN")
Or in Twig:
user.granted("USER_ADMIN")
If you need to check a role for the current user, you can do this in Twig:
app.user.granted("USER_ADMIN")
Note: the variable "app" is globally defined.
Note 2: this code may throw an exception if you use it outside the secured area of your app, since app.user would be NULL.
Upvotes: 0
Reputation: 5453
The other answers have you pass the container instead of the authorization checker. While they work they create a tight dependancy on the container making it harder to migrate your code to other projects. Instead you should only pass the authorization checker.
Here is an example taken from the symfony docs.
app/config/services.yml
services:
newsletter_manager:
class: "AppBundle\Newsletter\NewsletterManager"
arguments: ["@security.authorization_checker"]
src/Appbundle/Newsletter/NewsletterManager.php
namespace AppBundle\Newsletter;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
// ...
class NewsletterManager
{
protected $authorizationChecker;
public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
public function sendNewsletter()
{
if (false === $this->authorizationChecker->isGranted('ROLE_NEWSLETTER_ADMIN')) {
throw new AccessDeniedException();
}
// ...
}
// ...
}
Upvotes: 13
Reputation: 1120
The answer is that to be able to use Symfony2 classes in service you need to provide service with a container.
Service definition:
services:
/.../:
class: /.../
arguments: ['@service_container']
Service file:
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
class globalHelper {
private $container;
public function __construct(Container $container) {
$this->container = $container;
}
Upvotes: 0