Nefunguje inject autentikátoru do presenteru
- Džůny
- Člen | 19
Ahoj, mám aplikaci rozdělenou na dva moduly, Admin a Front, a napsal jsem si dva autentikátory. Bůhvíproč mi ale v Presenteru nejdou injectnout.
Třída FrontAuthenticator:
namespace App\Model\Security;
use Nette,
App\Model\BaseFacade;
/**
* Front authenticator class.
*/
class FrontAuthenticator extends BaseFacade implements Nette\Security\IAuthenticator
{
/** @var string */
protected $table = 'users';
/**
* Performs an authentication.
* @return Nette\Security\Identity
* @throws Nette\Security\AuthenticationException
*/
public function authenticate(array $credentials)
{
…
}
}
V configu mám:
services:
frontAuthenticator: {class: App\Model\Security\FrontAuthenticator, autowired: false}
A v BasePresenteru si ho chci injectnout:
/** @var \App\Model\Security\FrontAuthenticator @inject */
public $frontAuthenticator;
Jenže pořád dokola dostávám jen:
Nette\InvalidStateException
Service of type App\Model\Security\FrontAuthenticator used in @var annotation at App\Front\Presenters\BasePresenter::$frontAuthenticator not found. Did you register it in configuration file?
Musím to udělat jinak, předáním přes konstruktor presenteru? Chtěl jsem se konstruktoru vyhnout, kvůli constructor hell v potomcích BasePresenteru…
- App\Front\Presenters\BasePresenter(@App\Model\Security\FrontAuthenticator)
Nevím kde může být chyba. Namespace mám snad dobře, v Containeru se normálně vytvoří:
'frontAuthenticator' => 'App\Model\Security\FrontAuthenticator',
Předem díky za každou radu…
Edit.
Nette 2.3.4, cache jsem smazal.
Editoval Džůny (26. 7. 2015 14:07)
- Matey
- Člen | 142
Ahoj,
nedávno som tiež potreboval osobitný authenticator na front/admin a tu sa
ponúka jednoduché riešenie :)
proste sa vyhneš IAuthenticatoru
ešte kompletná ukážka:
<?php
namespace App\Model;
use Kdyby\Doctrine\EntityManager;
use Nette\Object;
use Nette\Security;
class FrontAuthenticator extends Object
{
/**
* @var EntityManager
*/
private $entityManager;
/**
* @var Security\User
*/
private $user;
/**
* @param EntityManager $entityManager
* @param Security\User $user
*/
public function __construct(EntityManager $entityManager, Security\User $user)
{
$this->entityManager = $entityManager;
$this->user = $user;
}
/**
* @param $email
* @param $password
* @throws Security\AuthenticationException
*/
public function login($email, $password)
{
$customer = $this->entityManager->getRepository(Customer::class)->findOneBy(['email' => $email]);
if (!$customer) {
throw new Security\AuthenticationException('Bad EMAIL', Security\IAuthenticator::IDENTITY_NOT_FOUND);
} elseif (!Security\Passwords::verify($password, $customer->password)) {
throw new Security\AuthenticationException('Bad PASSWORD', Security\IAuthenticator::INVALID_CREDENTIAL);
} elseif (Security\Passwords::needsRehash($customer->password)) {
$customer->setPassword($password);
$this->entityManager->flush();
} else {
$this->user->getStorage()->setNamespace('Front');
$this->user->login(new Security\Identity($customer->id, [$customer->role]));
}
}
}
?>
a zaregistrovať ako službu
- Zax
- Člen | 370
@Šaman To je právě hroznej opruz, náhodou to bude chtít nějaká knihovna nebo něco a už to musíš předělávat. Mně v Nette trochu chybí možnost zapnout/vypnout autowire zvlášť podle classy nebo podle interfacu. Řešení co postnul @Matey je IMO pro tenhle případ nejlepší, prostě si napsat vlastní služby, ty vyžadovat, neřešit interface.
- Džůny
- Člen | 19
@Matey Díky za odkaz a ukázku! :) Vyhnout se IAuthenticatoru bude asi nejsnazší.
@Šaman Áha. Díky za vysvětlení. Když zruším vypnutí
autowired
, tak mi Laděnka hlásí:
Nette\DI\ServiceCreationException
Service 'security.user': Multiple services of type Nette\Security\IAuthenticator found: adminAuthenticator, frontAuthenticator
…což je správně, protože jak FrontAuthenticator
tak
AdminAuthenticator
implementují IAuthenticator
. Už
jsem z toho zmatený. Vyřeším to tak jak psal @Matey.
Editoval Džůny (26. 7. 2015 14:46)
- Šaman
- Člen | 2666
Na usera jsem zapomněl. Za sebe musím říct, že mi tahle provázanost
uživatel – autentikátor – $presenter->user
a
$user
v šabloně docela vadí.
Pak je druhá možnost – nechat ten sekundární autentikátor
autowired: false
, ale do FrontPresenteru (nebo i všech jeho
potomků) ho injectuješ ručně. Tedy na straně presenteru si vytvoříš
setter ((set|inject)Autenticator
) a zavoláš ho z configu pomocí
decoratoru
decorator:
App\Front\Presenters\BasePresenter:
setup:
- injectAutenticator(@App\Model\Security\FrontAuthenticator)
- Džůny
- Člen | 19
Zezačátku mi to připadalo dost matoucí, než jsem si v API našel, že
jsou to automaticky předávané magické property a všechno okolo toho. Ono
stejně teď po rozdělení UserStorage
podle NS Admin/Front si
musím v BasePresenteru předávat
$this->template->user = $this->getUser()
ručně a metodu
getUser() mít přetíženou:
public function getUser()
{
$user = parent::getUser();
$user->getStorage()->setNamespace('Front');
return $user;
}
Asi by se mi líbilo, kdyby šel celý problém řešit nějak pěkněji, jen mě nenapadá jak.
Každopádně děkuji za rady, už jsem to přepsal a funguje to pěkně.
Edit. Mimochodem, kde se všichni naučili ta kouzla s configem? :) Stačí více porozumět Nette a principu vytváření Containteru a ono to půjde samo?
Editoval Džůny (26. 7. 2015 18:42)
- Džůny
- Člen | 19
Tak jak to napsal @Matey, jde to poskládat dohromady z toho odkazu
na nette-multi-authenticator
a ukázky kterou napsal.
Ještě kdyby někdo potřeboval uživatele „schovaného“ v Namespace dostat do komponenty přes DI a nešlo mu to:
public function __construct(\Nette\Security\User $user)
{
$this->user = $user->getStorage()->setNamespace('Front');
}
private function doSomething()
{
$this->user->identity…
}
Je potřeba ten Namespace znovu nastavit.
Nebo by šlo komponentu zdědit od UI\Control
, pokud už není,
a dostat se přes $this->getPresenter()
na přetíženou metodu
getUser()
(můj předchozí post), ale to mi připadá nečisté
(poruší se tím princip DI?).
Editoval Džůny (27. 7. 2015 1:55)
- Pavel Janda
- Člen | 977
Přetěžování metod znamená něco jiného. PHP neumožňuje přetěžovat metody v tom klasickém slova smyslu. Používá sice termín „class methods overloading“, ale pro něco (implementačně) jiného.
- Džůny
- Člen | 19
Pardon, tak tedy přepsanou, ať jsme přesní.
Ještě prosím někoho o vysvětlení: když si injectnu
Nette\Security\User
do různých komponent, proč v některých
Namespace na Front nastavený je, a v některých ne? Asi mi pořád
něco uniká…
Edit: Už jsem asi našel téma které toto řeší.
Editoval Džůny (27. 7. 2015 22:11)