如何让Symfony用户提供程序在EntityRepository上执行方法?

时间:2014-07-13 14:38:26

标签: php symfony

我有一个Symfony 2应用程序,它使用Cosign单点登录解决方案进行身份验证(https://github.com/fmfi-svt/cosign-bundle),然后使用自定义用户提供程序设置角色并处理任何特定路由的授权。角色主要基于不同LDAP组中的成员资格来设置,但我还需要查看用户在数据库中是否具有“已​​批准”状态。这部分的LDAP部分正在运行,但我无法弄清楚如何允许用户提供程序为我已设置为服务的实体调用EntityRepository方法。基本上,从我的User Provider内部,我希望能够使用Person实体存储库,如下所示:

$status = $personRepository->findStatusByUsername();

我假设我需要使用依赖注入来使EntityRepository对用户提供者可用,但我似乎无法弄清楚如何做到这一点。问题似乎归结为用户提供程序未实例化为对象的事实,因此我无法使用$ this。我在下面的代码中显示的最新尝试使用了属性类型依赖注入方法,但是当我尝试在is_approved()方法中使用它时,Symfony仍然认为常量$ personRepository是未定义的。

  

错误:C:\ xampp55 \ htdocs \ symtran2 \ src \ Ginsberg \ TransportationBundle \ Security \ User \ UserProvider.php第220行中未定义的类常量'personRepository'

作为背景,登录用户和Person实体之间的应用程序有所不同。最常见的情况是登录用户是管理人员的管理员,尽管Person也可以登录并管理他们自己的信息(例如,在系统中为自己预留。)登录用户的身份由Cosign提供,这使用户的用户名在$ _SERVER ['REMOTE_USER']中可用。因此,您始终可以通过检查该值来告知谁已登录。这样做的结果是不需要“用户”表来跟踪用户名。但是,有两个与用户信息相关的类:

  • User类实现UserInterface和EquatableInterface和 似乎是Symfony安全系统使用的对象 管理授权。 (我按照以下内容创建了这个类 Cookbook中有关创建自定义用户提供程序的说明: http://symfony.com/doc/current/cookbook/security/custom_provider.html)。

  • 上面提到的Person实体,它跟踪有关的信息 系统中用户的状态,例如给定Person的阶段 在审批过程中。

我已尝试将PersonRepository放入服务中,然后将该服务提供给User Provider服务,如下所示:

parameters:
ginsberg_transportation.user.class: Ginsberg\TransportationBundle\Services\User
user_provider.class: Ginsberg\TransportationBundle\Security\User\UserProvider

services:
  ginsberg_user:
    class: "%ginsberg_transportation.user.class%"
 user_provider:
    class: "%user_provider.class%"
    properties:
      personRepository: "@ginsberg_person.person_repository"
  ginsberg_transportation.form.type.person:
    class: Ginsberg\TransportationBundle\Form\Type\PersonType
    tags:
      - { name: form.type, alias: person }
  ginsberg_person.person_repository:
    class: Doctrine\ORM\EntityRepository
    factory_service: doctrine.orm.default_entity_manager
    factory_method: getRepository
    arguments:
      - Ginsberg\TransportationBundle\Entity\Person

UserProvider类很长,但相关部分是:

namespace Ginsberg\TransportationBundle\Security\User;

use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Ginsberg\TransportationBundle\Entity\Person;
use Doctrine\ORM\EntityRepository;


class UserProvider implements UserProviderInterface
{
  public $personRepository;

   protected static $_host = 'ldap.itd.umich.edu';
    // The umbrella group that lists the subgroups of eligible drivers
    protected static $_eligible_group = 'ginsberg transpo eligible';
    protected static $_admin_group = 'ginsberg transportation admins';
    protected static $_superuser_group = 'ginsberg transportation superusers';
    protected static $_pts_group = 'ginsberg pts staff';
    public static $_pts_group_email = 'ginsberg-pts-staff@umich.edu';

    public function loadUserByUsername($uniqname)
    {
      $password = "admin";
      $salt = "";
      $roles = array();

      if (self::is_authenticated()) {
        if (self::is_superuser() && self::is_approved()) {
          $roles[] = 'ROLE_SUPER_ADMIN';
        } elseif (self::is_admin() && self::is_approved()) {
          $roles[] = 'ROLE_ADMIN';
        } elseif (self::is_eligible() && self::is_approved()) {
          $roles[] = 'ROLE_USER';
        }

        return new User($uniqname, $password, $salt, $roles);
      }

      throw new UsernameNotFoundException(
      sprintf('Username "%s" does not exist.', $uniqname));
    }

    public function refreshUser(UserInterface $user) {
      if (!$user instanceof User) {
        throw new UnsupportedUserException(
          sprintf('Instances of "%s" are not supported.', get_class($user))
        );
      }

      return $this->loadUserByUsername($user->getUsername());
    }

    public function supportsClass($class) {
      return $class === 'Ginsberg\TransportationBundle\Security\User\User.php';
    }

    /**
     * Gets uniqname based on value of $_SERVER['REMOTE_USER'] or supply hard-coded value for testing
     *
     * @return string User's uniqname or false if not found
     */
    public static function get_uniqname()
    {
      // If we are in a cosign environment, return the user uniqname from
      // REMOTE_USER
      if (isset( $_SERVER['REMOTE_USER'] ) && !empty( $_SERVER['REMOTE_USER'] )) {
        return $_SERVER['REMOTE_USER'];
      }

      // for local debug:
      if(!isset( $_SERVER['REMOTE_USER'] ) &&
          $_SERVER[ 'SERVER_NAME' ] === 'localhost') {
        return 'ericaack';
          }

    return false;
    }


    /**
     * Check whether user is logged in through Cosign.
     *
     * @return boolean Whether or not the user is authenticated
     */
    public static function is_authenticated()
    {
      if (self::get_uniqname() != False) {
        return True;
      }
      return False;
    }

    /**
     * Checks whether or not user is approved in Ginsberg transpo database
     *
     * @return boolean Whether user is approved
     */
    public static function is_approved()
    {
      $uniqname = self::get_uniqname();
      $personRep = self::personRepository;
      $status = $personRep->findStatusByUniqname($uniqname);

      return($status == 'approved') ? TRUE : FALSE;

    }

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

我能够通过在UserProvider类中使用注入来完成此操作(Symfony 3)。我在类中设置了一个类变量和setter方法。另外,我必须在services.yml文件中设置服务。我会告诉你这两个。

UserProvider Class

use Doctrine\ORM\EntityRepository;
//make sure to include all other relevant uses!!

class WebserviceUserProvider implements UserProviderInterface{
private $er; //**HERE IS WHERE WE STORE THE EntityRepository**

/**
 * {@inheritDoc}
 * @see \Symfony\Component\Security\Core\User\UserProviderInterface::loadUserByUsername()
 */
public function loadUserByUsername($username)
{
    if ($username != '') {
        //WE CAN USE THE EntityRepository here!
        $user = $this->er->loadUserByUsername($username);
        if (!empty($user)){
            //Call the UserService or whatever you need to do
        }           
    }

    throw new UsernameNotFoundException(
            sprintf('Username "%s" does not exist.', $username)
            );
}

    /**
     * Injection method to allow us to use the EntityRepository for User
     * here. Otherwise we don't have access to it.
     * @param EntityRepository $em
    */
    public function setEr(EntityRepository $er){
        $this->er = $er;
    }

    //Include any other methods here you need for your UserProvider Class
    //I've left them out for brevity
}

<强> services.yml 您必须创建存储库服务,并将其链接到您需要使用它的UserProvider!

services:
    my_repository:
        class: Doctrine\ORM\EntityRepository
        factory: ['@doctrine.orm.default_entity_manager', getRepository]
        arguments:
            - AcmeBundle\Entity\User
    app.webservice_user_provider:
        class: AcmeBundle\Security\User\WebserviceUserProvider
        calls:
             - [setEr, ['@my_repository']]