ACL = Access Control List je SEZNAM – jak získat seznam toho co uživatel může?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Honza Kuchař
Člen | 1662
+
0
-

Ahoj,
netušíte někdo prosím vás, jak dostat z jinak perfektní třídy Permission seznam toho, co uživatel může. Potřebuji takovýto seznam dopravit na klienta, kde se podle něj vygeneruje GUI. Je to možné? Byla by škoda, jednou ládovat data do třídy Permission a pak dělat další vlastní implementaci na získání toho seznamu.

Výsledek by měl vypadat, jako přehled zdrojů a privilegií nad nimi. V případě, že uživatel může nad něčím vše, použije se hvězdička, či se nějak jinak označí.

Pěkný večer všem zde přeje,
Honza Kuchař

Filip Procházka
Moderator | 4668
+
0
-

ACL máš pravděpodobně někde uložené, je tak?
Do Permissions to musíš načíst pokaždé po startu znova (cachování na tom nic nemění)
Takže máš někde uloženej strom závislostí s Resources, Roles a Privileges

proč to teda nevygeneruješ z toho? je to 1 max 3 SQL, popř si extendnout Permissions a udělat tam jednoduchou funkci na vycucnutí cache

Honza Kuchař
Člen | 1662
+
0
-

Ono to s tím vytažením z databáze, zase tak jednoduché není. Zdroje a role mají dodiče, tedy jsou dědičné…

A z Permission cache „vycucnout“ nejde, protože je private.

PS: Tady ten „seznam“ toho, co uživatel může, by asi měl souviset s Identity, protože se generuje pro uživatele…

Filip Procházka
Moderator | 4668
+
0
-

myslím že v to hledáš moc vědu :)

inspiroval bych se tady
https://forum.nette.org/…control-list

+pár podmínek vyřeší filtr pro uživatele

Honza Kuchař
Člen | 1662
+
0
-

Ano, ano, vyšel jsem z toho a myslím, že jsem na správné cestě. Akorát tedy nevím, když mám třeba třicet zdrojů a pět privilegií = 150 výsledků, to je docela dost. Ale co, pravda, načítá se to jen při přihlášení uživatele… :) Pak sem dám, to co jsem tedy upravil. :)

Honza Kuchař
Člen | 1662
+
0
-

AccessSumaryModel

class AccessSummaryModel extends Object {

	/** @var array */
	private $summary = array();

	/**
	 * @param array Array of roles
	 */
	public function __construct(array $roles) {
		$aclModel = new AclModel();

		$resources = $aclModel->getResources();
		$privileges = $aclModel->getPrivileges();

		$acl = Environment::getService("Nette\Security\IAuthorizator");
		$i = 0;
		foreach ($resources as $res) {
			$res_array = array();
			foreach ($privileges as $pri) {
				foreach ($roles as $role) {
					if ($acl->isAllowed($role, $res->name, $pri->name)) {
						$res_array[] = $pri->name;
						break 1; // Další privilegium...
					}
				}
			}
			if(count($res_array) < 1) continue;
			if(count($res_array) == count($privileges)) {
				$res_array = "*";
			}
			$this->summary[$res->name] = $res_array;
		}
	}

	/**
	 * @return  array Resources and privileges for current roles
	 */
	public function getAccess() {
		return $this->summary;
	}

}

AclModel (komunikace s databází)

class AclModel extends Object {
	const ACL_TABLE = 'ACL';
	const PRIVILEGES_TABLE = 'Privilegia';
	const RESOURCES_TABLE = 'Zdroje';
	const ROLES_TABLE = 'Role';

	public function getRoles() {
		return dibi::fetchAll('SELECT `r1`.`KlicovyNazev` AS `name`, `r2`.`KlicovyNazev` as `parent_name`
				FROM [' . self::ROLES_TABLE . '] AS `r1`
				LEFT JOIN [' . self::ROLES_TABLE . '] AS `r2` ON (`r1`.`IdRodice` = `r2`.`IdRole`)
				ORDER BY `r1`.`IdRole`
                              ');
	}

	public function getResources() {
		return dibi::fetchAll('SELECT `r1`.`KlicovyNazev` AS `name`, `r2`.`KlicovyNazev` as `parent_name`
				FROM [' . self::RESOURCES_TABLE . '] AS `r1`
				LEFT JOIN [' . self::RESOURCES_TABLE . '] AS `r2` ON (`r1`.`IdRodice` = `r2`.`IdZdroje`)
				ORDER BY `r1`.`IdZdroje`');
	}

	public function getPrivileges() {
		return dibi::fetchAll('SELECT `r1`.`KlicovyNazev` AS `name`
				FROM [' . self::PRIVILEGES_TABLE . '] AS `r1`
				ORDER BY `r1`.`IdPrivilegia`
		      ');
	}

	public function getRules() {
		$q = dibi::query('
		SELECT
                `a`.`Povolit` as `allowed`,
                `ro`.`KlicovyNazev` AS `role`,
                `re`.`KlicovyNazev` AS `resource`,
                `p`.`KlicovyNazev`  AS `privilege`

                FROM [' . self::ACL_TABLE . '] AS `a`
                JOIN [' . self::ROLES_TABLE . '] AS `ro` ON (`a`.`IdRole` = `ro`.`IdRole`)
                LEFT JOIN [' . self::RESOURCES_TABLE . '] AS `re` ON (`a`.`IdZdroje` = `re`.`IdZdroje`)
                LEFT JOIN [' . self::PRIVILEGES_TABLE . '] AS `p` ON (`a`.`IdPrivilegia` = `p`.`IdPrivilegia`)
                /*ORDER BY `a`.`Id` ASC*/
		');
		$q->setType('access', Dibi::BOOL);
		return $q->fetchAll();
	}

}

Authorizator

class Authorizator extends Permission {

	public function  __construct() {
		$model = new AclModel();

		foreach($model->getRoles() as $role)
		    $this->addRole($role->name, $role->parent_name);

		foreach($model->getResources() as $resource)
		    $this->addResource($resource->name, $resource->parent_name);

		foreach($model->getRules() as $rule)
		    $this->{$rule->allowed == true ? 'allow' : 'deny'}($rule->role, $rule->resource, $rule->privilege);
	}

}

Výsledek (souhrn práv uživatele):

{
    "studio": [
        "zobrazit"
    ],
    "vyroba": [
        "zobrazit"
    ],
    "zakazkaZakladni": "*",
    "zakazkaPokrocila": "*"
}