Při tvorbě assertion pro autorizaci se místo objektů vrací string

Operator21
Člen | 2
+
0
-

Zdravím, zkouším si vytvořit kontrolu oprávnění, konkrétně aby vlastník článku mohl daný článek odstranit aniž by mohl mazat ostatním, postupoval jsem podle dokumentace na https://doc.nette.org/…uthorization a zasekl jsem se u tvorby assertion.

use Nette\Security\Permission;

class AuthorizatorFactory {
	const ROLE_ADMIN = "admin";
	const ROLE_USER = "user";

	const RESOURCE_ARTICLE = "article";
	const RESOURCE_USER = "user";

	const ACTION_CREATE = "create";
	const ACTION_UPDATE = "update";
	const ACTION_DELETE = "delete";

	public static function create(): Permission {
		$acl = new Permission();

		// add resources
		$acl->addResource(self::RESOURCE_USER);
		$acl->addResource(self::RESOURCE_ARTICLE);

		//add roles
		$acl->addRole(self::ROLE_ADMIN);
		$acl->addRole(self::ROLE_USER);

		//admin has total control
		$acl->allow(self::ROLE_ADMIN, self::RESOURCE_USER);
		$acl->allow(self::ROLE_ADMIN, self::RESOURCE_ARTICLE);

		//if user is author -> allow deletion
		$assertion = function (Permission $acl, string $role, string $resource, string $privilege): bool {
			$role = $acl->getQueriedRole();
			$resource = $acl->getQueriedResource();
			return $role->getId() === $resource->getOwner()->getId();
		};
		$acl->allow(self::ROLE_USER, self::RESOURCE_ARTICLE, self::ACTION_DELETE, $assertion);

		return $acl;
	}
}

Dostávám chybu: Error: Call to a member function getId() on string in /app/app/Model/AuthorizatorFactory.php:32
Což je tato část return $role->getId() === $resource->getOwner()->getId();

Logicky to na mě řve, že se snažím vyvolat funkci ze stringu, ale co jsem pochopil z toho stručného návodu v dokumentaci, tak metody getQueriedRole() a getQueriedResource() vrátí objekt podle funkcí getRoleId() respektivě getResourceId().

V třídách klasicky implementuju interface:

  • User implementuje jak Role tak i Resource (doufám, že to je tak správně, pokud chci mít i správu uživatelů)
public function getRoleId(): string {
	# role se získává z databáze, hodnoty jsou ekvivaletní konstantám v authorizátoru
	return $this->role;
}

public function getResourceId(): string {
	return AuthorizatorFactory::RESOURCE_USER;
}
  • Article implementuje pouze Resource
public function getResourceId(): string {
	return AuthorizatorFactory::RESOURCE_ARTICLE;
}

Pokud klasicky ověřím pomocí $user->isAllowed($otherUser) nebo $user->isAllowed($article) a $user má v tu chvíli roli admin, tak všechno funguje jak má, ale jakmile má roli user tak se to dostane k té chybě v assertion.

Procházel jsem si i dokumentaci api https://api.nette.org/…mission.html#… ale o moc víc informací mi to neposkytlo.

Věděl by někdo co dělám špatně?

dakur
Člen | 493
+
0
-

Co je špatně, to nevím, ale můžeš zjistit, že jestli se ta chyba týká $role->getId() nebo $resource->getOwner()->getId() (obojí má getId()). Pak se můžeš podívat, co je v tom teda za string a proč tam není objekt (prokliknutím do dané metody/proměnné).

Editoval dakur (23. 6. 2022 10:05)

Operator21
Člen | 2
+
0
-

Vyřešil jsem to, jakmile se používá funkce $user->isAllowed($article), tak $article se sice předá jako instance na objekt, ovšem $user už ne, podle mě se předá pouze role z identity a o objektu se už neví.

Vytvořil jsem si tedy statickou referenci na $acl v AuthorizationFactory (přiřazuju si ji těsně před return $acl) a na tu si šahám v presenteru, kde ji používám pomocí $acl->isAllowed($loggedUser, $article, "delete"), kde $loggedUser je instance objektu User získaná pomocí id v identitě. Jestli to je ideální řešení nevím, ale je funkční.