Symfony / sfDoctrineGuard Условные разрешения - PullRequest
1 голос
/ 13 сентября 2010

Я обдумываю лучший способ реализации условных разрешений, т. Е. Пользователи и команды являются m-to-m. Но каждая команда также имеет отношение «лидер» 1 к m с таблицей User.

Для простоты, скажем, у нас есть два уровня разрешений: «Пользователь» и «Администратор». Затем, скажем, только определенное задание администрирования команды, то есть групповые электронные письма, может отправлять только руководитель этой команды.

В настоящий момент каждое действие, которое является специфическим для руководителей групп, запрашивает базу данных, чтобы проверить, является ли текущий пользователь лидером группы (учитывая, что пользователь может возглавлять множество команд). Лично мне не нравится видеть "if ($ user-> isLeader ($ team))" повсюду.

Я рассмотрел вопрос настройки списка команд, возглавляемых пользователем в сеансе пользователя при входе в систему (ala phpBB), или использования фильтра symfony для того же.

Однако при первом подходе данные могут устареть в случае, когда другой пользователь может сменить лидера команды. Второй подход требует дополнительного запроса к базе данных при каждой загрузке страницы.

Есть идеи получше? примечание: в одном проекте есть несколько приложений, которым необходимо использовать одну и ту же модель разрешений (т. е. backend и api)

Ответы [ 2 ]

0 голосов
/ 14 сентября 2010

вижу 2 варианта:

Переопределить sfDoctrineGuardUser::getGuardUser()

Переопределите метод getGuardUser sfDoctrineGuardUser, чтобы получить команды, когда он получит пользователя. Это требует дополнительного левого соединения, но сохраняет ваши последующие запросы.

/**
* Overridden getGuardUser to automatically fetch Teams with User
* @see plugins/sfDoctrineGuardPlugin/lib/user/sfGuardSecurityUser#getGuardUser()
*/
public function getGuardUser()
{
  if (!$this->user && $id = $this->getAttribute('user_id', null, 'sfGuardSecurityUser'))
  {
    $this->user = sfGuardUserTable::findUserByIdWithTeams($id); //write this query to fetch a user with his teams

    if (!$this->user)
    {
      // the user does not exist anymore in the database
      $this->signOut();

      throw new sfException('The user does not exist anymore in the database.');
    }
  }

  return $this->user;
}

Затем вы можете добавить учетные данные пользователя, основываясь на его командах, через фильтр или переопределив hasCredential.

Неправильный статус кэшированных команд

Если вам не нужны дополнительные запросы, единственная дополнительная опция, которую я вижу, - это использование глобального кэша. Это будет включать в себя следующее:

  • Кэшировать команды пользователя или командные учетные данные при входе в систему
  • Когда лидер команды удален или добавлен, сделайте что-то вроде apc_add(team_invalid_[team_id], true, [length_of_session])
  • Каждый раз, когда добавляются учетные данные пользователя (с помощью одного из методов, описанных в первом варианте), проверяйте кэш, чтобы убедиться, что они недействительны.
0 голосов
/ 13 сентября 2010

Я добился чего-то подобного, переписав метод hasCredential в myUser для выполнения пользовательских проверок, когда требуются определенные учетные данные.

например:

public function hasCredential($credential, $useAnd = true) {

  // make sure the symfony core always passes the team leader permission, we handle it later ourselves
  $this->addCredential('team_leader');
  $ret = parent::hasCredential($credential, $useAnd);

  // if other checks have failed, return false now, no point continuing
  if (!$ret) return false;

  if ($credential == 'team_leader' || (is_array($credential) && in_array('team_leader', $credential))) {
    // do stuff here. in this example, we get the object from a route and check the user is a leader
    $route = sfcontext::getinstance()->getRequest()->getAttribute('sf_route');
    if (!$route instanceof sfObjectRoute) {
      throw new sfConfigurationException(sprintf('team_leader credential cannot be used against routes of class %s - must be sfObjectRoute', get_class($route)));
    }
    return $this->isLeader($route->getObject());
  }
  return $ret;
}

Затем вы можете добавить учетные данные «team_leader» в security.yml, как и любые другие.

Очевидно, это зависит от того, используете ли вы sfObjectRoutes, поэтому, возможно, вам это не подойдет, если вы не можете этого сделать и не можете адаптировать то, что используете, но я думаю, что это хорошее решение, когда вы можете его использовать!

Если вы беспокоитесь о дополнительных запросах, вы можете посмотреть на обертывание некоторого кэширования вокруг вызовов isLeader.

...