1

条件付きアクセス許可を実装する最善の方法、つまりユーザーとチームが m 対 m であることを考えています。ただし、各チームには、ユーザー テーブルとの 1 対 m の「リーダー」関係もあります。

簡単にするために、「ユーザー」と「管理者」の 2 つの権限レベルがあるとします。次に、特定のチーム管理タスク、つまりグループ メールのみを、そのチームのリーダーのみが送信できるとしましょう。

現時点では、チーム リーダーに固有のすべてのアクションがデータベースにクエリを実行し、現在のユーザーがチーム リーダーであるかどうかを確認します (1 人のユーザーが多くのチームを率いる可能性があることに注意してください)。個人的には、"if($user->isLeader($team))" がいたるところにあるのが好きではありません。

ログイン時のユーザーセッション(ala phpBB)でユーザーが率いるチームのリストを設定するか、symfonyフィルターを使用して同じことを行うことを検討しました。

ただし、最初のアプローチでは、別のユーザーがチームのリーダーを変更する可能性がある場合、データが古くなる可能性があります。2 番目の方法では、ページの読み込みごとに追加のデータベース クエリが必要になります。

より良いアイデアはありますか?注: 1 つのプロジェクトに複数のアプリがあり、同じパーミッション モデル (つまり、バックエンドと API) を共有する必要があります。

4

2 に答える 2

0

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])
  • (最初のオプションで説明した方法のいずれかを使用して) ユーザーの資格情報が追加されるたびに、キャッシュをチェックしてそれらが無効かどうかを確認します。
于 2010-09-14T03:14:17.057 に答える
0

myUser の hasCredential メソッドをオーバーライドして、特定の資格情報が必要なときにカスタム チェックを実行することで、同様のことを達成しました。

例えば:

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 呼び出しにキャッシングをラップすることを検討できます。

于 2010-09-13T09:28:23.753 に答える