Více autentikatoru s cookie

Zdeno1981
Člen | 115
+
0
-

Zdravím,

mám podle dokumentace vytvořený autentikator

final class Authenticator implements Nette\Security\Authenticator, Nette\Security\IdentityHandler
{
	public function authenticate(string $username, string $password): SimpleIdentity
	{
		...
	}

	public function sleepIdentity(IIdentity $identity): SimpleIdentity
	{
		...
	}

	public function wakeupIdentity(IIdentity $identity): ?SimpleIdentity
	{
		...
	}
}

V konfiguračním souboru použivám nastavení pro cookie

security:
	authentication:
		storage: cookie

services:
	- Authenticator

Toto všechno funguje jak má až do chvíle, kdy jsem potřeboval použit druhý authenticator pro frontend modul.

Jakmile podle dokumentace použuju tuto metodu, dostanu chybu: „Call to undefined method Nette\Bridges\SecurityHttp\CookieStorage::setNamespace().“

public function checkRequirements($element): void
{
	$this->getUser()->getStorage()->setNamespace('backend');
	parent::checkRequirements($element);
}

Když výše zmíněnou metodu odstraním a nastavím Authenticator tímto způsobem:

services:
	-
		create: Authenticator
		autowired: self

Tak se do aplikace sice přihlásím, ale dostanu tuto chybu „Role ‚authenticated‘ does not exist.“
Nepředá se identita, jak by měla, nejsou tam data ani role.

Nette\Security\SimpleIdentity
id: '4ca4a100353933efd7942c878523fc00'
roles: array (0)
data: array (0)

Když odstraním nastavení pro cooke a metody sleepIdentity a wakeupIdentity tak to funguje.

security:

services:
	-
		create: Authenticator
		autowired: self

Nevím co se děje v hloubce při použití cookie s více autentikatoru, takže si s tím nevím rady, dokáže někdo poradit jak to vyřešit aby více autentikatoru fungovalo s cookie a metodami sleepIdentity a wakeupIdentity?

Editoval Zdeno1981 (14. 9. 2022 10:35)

Pepino
Člen | 256
+
+1
-

U cookie authenticatoru jde „namespace“ nastavit přes:

$this->user->getStorage()->setCookieParameters('front');

Editoval Pepino (14. 9. 2022 11:19)

Marek Bartoš
Nette Blogger | 1260
+
+1
-

Ona tam metoda setNamespace() není, cookie storage má setCookieParameters(‚backend‘)

Ale spíš než přepínat storage bych ti doporučil mít pro administraci a veřejnou část oddělené User služby, viz https://forum.nette.org/…okie-storage#…

Zdeno1981
Člen | 115
+
0
-

ok, díky, tohle člověk v dokumentaci nenajde, vyzkouším :)

Zdeno1981
Člen | 115
+
0
-

@MarekBartoš

tak jsem spáchal toto, dám to sem, kdyby někdo něco podobného taky řešil, nevím jestli to je ideální řešení, ale je funkční :)

Backend modul:

	securityAdmin.storage:
		create: Nette\Bridges\SecurityHttp\CookieStorage
		autowired: self
		setup:
			- setCookieParameters(name: adminLogin)

	securityAdmin.authenticator:
		create: App\Modules\Backend\Admin\Services\Repository\AuthRepository
		autowired: self

	securityAdmin.user:
		create: Nette\Security\User
		autowired: self
		arguments:
			storage: @securityAdmin.storage
			authenticator: @securityAdmin.authenticator

Frontend modul kde jsem to potřeboval:

	securityEfficiency.storage:
		create: Nette\Bridges\SecurityHttp\CookieStorage
		autowired: self
		setup:
			- setCookieParameters(name: efficiencyLogin)

	securityEfficiency.authenticator:
		create: App\Modules\Front\Efficiency\Services\Repository\EfficiencyAuth
		autowired: self

	securityEfficiency.user:
		create: App\Modules\Front\Efficiency\Services\Domain\EfficiencyUser
		arguments:
			storage: @securityEfficiency.storage
			authenticator: @securityEfficiency.authenticator

	efficiencyPresenter:
		create: App\Modules\Front\Efficiency\EfficiencyPresenter
		arguments:
			user: @securityEfficiency.user

Nicméně v Tracy baru není ikonka usera s identitou, ale to by neměl být problém pak doladit a přidat tam jednu ikonku pro jeden modul a druhou pro ten druhy a předat tam jednotlivé identity.

Editoval Zdeno1981 (16. 9. 2022 6:41)

Marek Bartoš
Nette Blogger | 1260
+
0
-

Když si nastavíš type ještě u securityEfficiency.user, tak ho nebudeš muset předávat manuálně

authenticator bych do Usera vůbec nepředával. Interface Authenticator vůbec nemusíš používat, stačí do User->login() předávat již ověřenou Identity

Pro custom usera můžeš Tracy panel přidat v jeho setupu. Myslím že to jde i v neonu, ale nikdy si nepamatuju jak, tak aspoň nástřel, jak by to mělo fungovat v extension:

final class CustomExtension extends \Nette\DI\CompilerExtension
{

	public function loadConfiguration(): void
	{
		$builder = $this->getContainerBuilder();

		$user = $builder->getDefinition('securityEfficiency.user');
		$user->addSetup('@Tracy\Bar::addPanel', [
			new \Nette\DI\Statement(\Nette\Bridges\SecurityTracy\UserPanel::class),
		]);
	}

}

Editoval Marek Bartoš (16. 9. 2022 7:07)

Zdeno1981
Člen | 115
+
0
-

Pokud nepředám authenticator do usera, tak se nepředává identita, sice se vytvoří cookie po spuštění sleepIdentity ale role a data jsou prázdná protože se nespustí metoda „wakeupIdentity“ koukal jsme se do Containeru co se tam děje a pokud je zápis v neonu takto:

services:
	- Authenticator

Tak se do usera automaticky v conteineru předá ten authenticator, bouhžel při tomto zápisu se již automaticky nepředá do usera.

services:
	-
		create: Authenticator
		autowired: self

ale vyzkouším tvůj návhr :)

Editoval Zdeno1981 (16. 9. 2022 8:06)

Marek Bartoš
Nette Blogger | 1260
+
+1
-

Máš pravdu, Authenticator fakt musíš mít :/ sleep/wakeup by ideálně měl být oddělený interface
https://github.com/…ty/issues/64

Editoval Marek Bartoš (16. 9. 2022 7:44)

Zdeno1981
Člen | 115
+
0
-

@MarekBartoš

S tím rozšířením jsem trochu bojoval, nemohlo mi to najít službu toho usera a navíc třída „Nette\DI\Statement“ je deprecated ale funkční řešení mám takto:

class UserAdminPanel extends CompilerExtension
{
	/** @var mixed|string|null */
	private mixed $panel;

	public function loadConfiguration(): void
	{
		$builder = $this->getContainerBuilder();
		$builder->addDefinition($this->prefix('panel'))
			->setFactory(UserPanel::class)
			->setArguments(['@securityAdmin.user']);

		$this->panel = $this->getContainerBuilder()
			->getByType(Bar::class);
	}


	public function afterCompile(ClassType $class): void
	{
		$init = $class->getMethods()['initialize'];
		$init->addBody('$this->getService(?)->addPanel($this->getService(?));', [
			$this->panel, $this->prefix('panel'),
		]);
	}
}

U toho modulu efficiency to mám v configu, protože nepotřebuji aby se ikonka zobrazovala u všech modulů v aplikaci.

	efficiencyPresenter:
		create: App\Modules\Front\Efficiency\EfficiencyPresenter
		arguments:
			user: @securityEfficiency.user
		setup:
			- @Tracy\Bar::addPanel(@securityEfficiency.userPanel)

	securityEfficiency.userPanel:
		create: Nette\Bridges\SecurityTracy\UserPanel(@securityEfficiency.user)
		autowired: self

Akorát u modulu efficiency jsou dvě ikonky toho usera :D ale to už je detail, jinak bych musel to rozšíření odebrat a pak každému presenteru v administraci přes config předávat službu …userPanel a to se mi nechce.

Editoval Zdeno1981 (16. 9. 2022 9:53)

Marek Bartoš
Nette Blogger | 1260
+
+1
-

Sorry, psal jsem to rozespalej a mám teď projekt na Nette 2.4… V Nette 3 je Statement v namespace Nette\DI\Definitions. Místo loadConfiguration() by zafungovalo beforeCompile() – pořadí provádění je loadConfiguration(), services z neonu, beforeCompile()

Zdeno1981
Člen | 115
+
0
-

ok, každopádně díky za pomoc :)

Editoval Zdeno1981 (16. 9. 2022 10:16)