Jak zabezpečit komponenty a jejich signály
- Jiří Nápravník
- Člen | 710
Jak řešit zabezpečení komponent, aby se mi tam nedostal někdo nepovolaný?
Presenter si ohlídám v checkRequirements, ale životní cyklus komponent není, či-li jak se to řeší, aby mi někdo nepodvrhl URL a nedostal se kam nemá?
Napadlo mě kontrola v createComponentXXX – to by mělo teoreticky stačit ne? Protože se komponenta nevyvoří…
Pokud mám ale komponentu, která bude mít továrničku ve více presenterech, je to nepraktické, tu kontrolu rozkopírovávat, jak to řešit pak? U každé handleMetody to kontrolovat? Nejde to třeba v attached či nějak podobně?
- Šaman
- Člen | 2666
Napadá mě:
- BaseControl a
__construct()
, ale jestli si budeš chtít sáhnout na presenter, takattached()
. V obou případech budeš muset důsledně volat parenta, pokud budeš chytít to té metody něco přidat. - Továrnička pomocí traity, nebo tovární třídy
- Jiří Nápravník
- Člen | 710
@Šaman Díky za reakci.
Přímo do BaseControlu nepotřebuji, protože těch komponent není tolik.
Nicméně je tohle v pořádku? Co jsem zkoušel, tak mě to nepustilo, ale jeslti něco nepřehlížím. ˇřeší to jak handle-metody tak onSuccess formulářů?
public function attached($presenter)
{
parent::attached($presenter);
if(!$this->authorizator->isAllowed('rss')){
$presenter->error('Not allowed', \Nette\Http\IResponse::S403_FORBIDDEN);
}
}
A ještě jedna věc. Když mám Presenter, který povoluje přístup v checkRequirements a jsou tam nějaké komponenty. Chápu správně, že člověk, co nemá přístup k Presenteru, tak se nedostane ani k těm komponentám a jejich handlerům?
A ještě jedna otázka stejně tak by to mělo řešit i případ, že mám komponentu zanořenou, taky by ho to nemělo pustit dále, že?
Ty továrny asi nechápu. Používám generované továrny, to bych si je musel asi napsat růčo, jako ukazuješ, že? A řešit to oprávnění v té samotné továrně?
Editoval Jiří Nápravník (9. 4. 2014 12:57)
- Šaman
- Člen | 2666
matej21 napsal(a):
@Šaman: https://github.com/…83eada6d311b
To jsme si nerozuměli. Já myslel něco takového:
<?php
class BaseControl
{
public function __construct()
{
# nějaká kontrola
}
}
class MyControl extends BaseControl
{
public function __construct()
{
parent::__construct(); # <-- tohle tu být musí, jinak žádná kontrola
# něco nového
}
}
?>
- Šaman
- Člen | 2666
Jiří Nápravník napsal(a):
A ještě jedna věc. Když mám Presenter, který povoluje přístup v checkRequirements a jsou tam nějaké komponenty. Chápu správně, že člověk, co nemá přístup k Presenteru, tak se nedostane ani k těm komponentám a jejich handlerům?
A ještě jedna otázka stejně tak by to mělo řešit i případ, že mám komponentu zanořenou, taky by ho to nemělo pustit dále, že?
Ty továrny asi nechápu. Používám generované továrny, to bych si je musel asi napsat růčo, jako ukazuješ, že? A řešit to oprávnění v té samotné továrně?
- Ano, komponenta nemůže existovat bez továrny v presenteru a presenter si na začátku kontroluje práva, takže by nemělo být možné zavolat signál komponenty, pokud nemáš práva k presenteru
- Totéž, jen komponenty nemají checkRequirements. Když ale nevytvořiš obalovou komponentu, nemůžeš pracovat s vnořenou.
- Ty továrny jsou na dvou místech.
- Nejprve tovární
třída – v tomto případě ji mám napsanou ručně, ale většinou se
používají generované továrničky. Výsledkem je v obou případech služba
(např.
FooFactory
), kterou si ijectnu třeba do presenteru a která mi umí vytvořit instanci nějaké třídy (Foo
). Tohle až tak nesouvisí s vytvářením komponent. - A potom potřebuješ metodu presenteru
createComponentFoo()
, aby měl presenter jak vytvořit konkrétní komponentu, zařadit ji do stromu komponent a vykreslit v šabloně pomocí{control foo}
. Tahle metoda může vytvořit instanci všelijak, třeba operátoremnew
, ale je z mnoha důvodů lepší, když využije tu výše popsanou tovární třídu. Nevýhoda je, že pokud chceš použít generovanou továrnu (tj, tovární třídu ti vygeneruje Nette), tak nemáš možnost do ni přidat třeba tu kontrolu práv. A tovární metodu (createComponentFoo
) musíš mít v každém presenteru, kde ji chceš využít a tak bys musel duplikovat kód kontroly, resp. celé továničky. A to právě řeší tahle traita. Traita je kus kódu, který můžeš (zjednodušeně řečeno) vložit na jiné místo. Takže inject metody i továrnička je v tomto případě u komponenty, továrničkacreateComponentLoginForm()
může být složitá a nikde se neopakuje a do všech presenterů bych pak jen vložil kód celé traity, tedy inject a vytvoření konkrétní komponenty (LoginForm
), takže po vložení traity mohu komponentu rovnou vykreslovat v šabloně.
- Nejprve tovární
třída – v tomto případě ji mám napsanou ručně, ale většinou se
používají generované továrničky. Výsledkem je v obou případech služba
(např.
- Jiří Nápravník
- Člen | 710
Díky za vyjasnění. Už chápu i jak jsi to myslel s těmi továrnami a traitou. Je to zajímavé řešení, ale já raději zůstanu u toho pořešení si opravnění v attached, jako jsem postnul výše. K tomu jsi se ale nevyjádřil, tak teď nevím, jestli tam není něco blbě…
- Jan Suchánek
- Člen | 404
@Šaman: Lze na ty komponenty využívat i události?
v továrně:
/**
* @return DiscussionControl
* @param string $thread
* @param string $role
*/
public function create($thread = '', $role = FALSE)
{
$discussion = new DiscussionControl($this->notes, $thread);
if($role){
$discussion->onAtached[] = function() use($discussion, $role){
if($isAdmin = $discussion->isEditable($role)){
$discussion->setEditable($isAdmin);
}
};
}
return $discussion;
}
v presenteru:
/**
* Továrnička na komponentu guestbook
* @return DiscussionControl
*/
public function createComponentGuestbook()
{
//$isAdmin = in_array('admin', $this->presenter->user->roles);
return $this->discussionControlFactory->create('guestbook', "admin");
}
Šlo by je pak nastavovat v neonu.
EDIT: Možná by pak ani komponenta nemusela mít $this->notes?
Editoval jenicek (9. 4. 2014 19:20)
- Jan Suchánek
- Člen | 404
Co si myslíte o tomhle?
/**
* @return DiscussionControl
*/
public function create($thread = '', $role = FALSE)
{
$discussion = new DiscussionControl($this->notes, $thread);
// nastavení role
$discussion->onAtached[] = function() use($discussion, $role){
$discussion->setRole($role);
};
// vyplnění výchozích hodnot do formuláře
$discussion->onLogged[] = function() use($discussion){
$discussion->setForm();
};
// událost při pokusu o smazání příspěvku
$discussion->onDeleted[] = function() use($discussion){
$discussion->setMessage('Příspěvek byl odstraněn.', 'success');
};
// událost při pokusu o přidání příspěvku
$discussion->onInserted[] = function() use($discussion){
$discussion->setMessage('Váš příspěvek byl přijat.', 'success');
};
// vykreslí ajaxově nebo přesměruje po přidání nebo smazání příspěvku, šlo by i po editaci, vlastně jinak by se kód opakoval
$discussion->onSuccess[] = function() use($discussion){
$discussion->setResponse();
};
return $discussion;
}
Nevim možná je to overhead, ale šlo mi ukázku použití událostí a možná jak podobné části kódu sloučit.
Editoval jenicek (9. 4. 2014 19:28)