【问题标题】:Symfony2 check user role in ServiceSymfony2 检查服务中的用户角色
【发布时间】:2020-08-02 19:38:57
【问题描述】:

如何检查 symfony2 服务代码中的用户角色?我应该简单地将用户角色对象发送到服务,还是有允许我从服务级别进行检查的解决方案?

【问题讨论】:

  • 您要检查什么?你想检查用户是否有角色吗?或者用户有权访问某些操作?
  • 我的服务定义了要添加到特定实体的可用标签。向实体添加某些标签需要用户具有给定的角色。我想在服务中检查给定用户是否可以添加给定标签(考虑到他拥有的角色)。因此,我需要在我的服务中访问有关用户角色的信息。

标签: symfony


【解决方案1】:

其他答案让您通过容器而不是授权检查器。当他们工作时,他们对容器产生了紧密的依赖,使得将代码迁移到其他项目变得更加困难。相反,您应该只通过授权检查器。

这是一个取自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();
        }

        // ...
    }

    // ...
}

【讨论】:

  • 恕我直言,这应该被接受。将容器传递给服务被认为是不好的做法。
【解决方案2】:

假设:

  • 你在你的服务中注入security.context

    public function __construct(SecurityContext $securityContext) {
      $this->securityContext = $securityContext;
    }
    
  • 您正在使用 FosUserBundle

  • 我正确理解了你的问题:-)

你应该可以做到:

$token = $this->securityContext->getToken();
if (empty($token)) {
    return [];
}
$user = $token->getUser();
if (empty($user)) {
    return [];
}
$roles = $user->getRoles();

2016 年 11 月 28 日更新

  1. 已更新答案以传递特定依赖项而不是整个容器,因为这是一种不好的做法(请参阅 @Shady 的评论)
  2. 请注意,从 Symfony 2.6 开始,SecurityContext 已被弃用,您应该改用 TokenStorage

【讨论】:

  • 感谢您提供将容器传递给服务的线索。这正是我所需要的。
  • 将容器传递给服务是一种不好的做法。
【解决方案3】:

答案是,为了能够在服务中使用 Symfony2 类,您需要使用容器来提供服务。

服务定义:

services:
  /.../:
    class: /.../
    arguments: ['@service_container']

服务文件:

使用 Symfony\Component\DependencyInjection\ContainerInterface 作为容器;

class globalHelper {    

    private $container;

    public function __construct(Container $container) {
        $this->container = $container;
    }

【讨论】:

  • 注入整个服务容器被认为是不好的做法。 (source 1) (source 2) 除非你有很好的理由,否则注入你需要的服务。
【解决方案4】:

编辑@Mick - 永远不要执行以下操作

请参阅here 了解更多信息。


我认为如果您在 User 实体中实现 isGranted 函数会容易得多:

Class User implements UserInterface {
    ...
    public function isGranted($role)
    {
        return in_array($role, $this->getRoles());
    }
}

您现在可以在应用程序的每一层轻松检查授予的角色。在 PHP 中:

$user->isGranted("USER_ADMIN")

或者在 Twig 中:

user.granted("USER_ADMIN")

如果您需要检查当前用户的角色,您可以在 Twig 中执行此操作:

app.user.granted("USER_ADMIN")

注意:变量“app”是全局定义的。

注意 2:如果您在应用程序的安全区域之外使用此代码,则可能会引发异常,因为 app.user 将为 NULL。

【讨论】:

  • 我正在使用FriendsOfSymfony/FOSUserBundle。问题是如何访问有关服务中的角色的信息?
  • 在大多数情况下,人们会定义一个分层的角色结构。这种方法的问题是没有考虑继承的角色。更好的是注入security.authorization_checker 服务。
【解决方案5】:

小心...

在涉及到安全性时要非常小心。不要这样做THIS

这是因为,您需要了解TokenInterfaceUserInterface 不同。

TokenInterface 是用户认证的接口 信息。

您必须使用它 - 如果您当前的服务中没有可用的令牌,请使用 SecurityContextAccessDecisionManager


注意:在 Symfony > 2.6 中,创建了一些 improvements,而 SecurityContext 已弃用,并分为 TokenStorageAuthorizationChecker。所以,你现在可以继续使用AuthorizationChecker


看!甚至 FOSUserBundle implementation 都在谈论它:

/**
 * 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);

看看它是如何工作的,比如getRolesHierarchical roles

数据库中的角色不可信 - 如果您从数据库中获取用户对象,并使用您的 getRoles() 或更糟糕的是您创建的特殊 isGranted($role),他们将不会拥有您期望的角色用户拥有。

This 应该是你的圣经,现在你可以理解它们之间的区别了:

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" 
}

当你有 security.yml

security:
    role_hierarchy:
        ROLE_ADMIN: [ROLE_ALLOWED_TO_SWITCH]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    • 2014-07-27
    • 2011-09-02
    • 2022-10-16
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多