Tato stránka obsahuje smyčku přesměrování + flashMessages v Modelu?
- Joacim
- Člen | 229
BasePresenter
<?php
namespace App\Presenters;
use Nette;
use App\Model;
/**
* Base presenter for all application presenters.
*/
abstract class BasePresenter extends Nette\Application\UI\Presenter {
/** @inject @var Nette\Database\Context */
public $database;
/** @persistent */
public $locale;
/** @var \Kdyby\Translation\Translator @inject */
public $translator;
/** @var \App\Model\Authenticator @inject */
public $authorizator;
public function startup() {
parent::startup();
if (!$this->getUser()->isLoggedIn()) {
if (!$this->authorizator->isSupportedBrowser()) {
$this->redirect("Login:unsupported");
} elseif ($this->authorizator->isBannedIp()) {
$this->redirect("Login:banned");
}
$this->redirect("Login:default");
}
}
}
Mám tento base presenter a prohlížeč mi hlásí
ERR_TOO_MANY_REDIRECTS.
Předtím jsem měl část:
if (!$this->authorizator->isSupportedBrowser()) {
$this->redirect("Login:unsupported");
} elseif ($this->authorizator->isBannedIp()) {
$this->redirect("Login:banned");
}
V login presenteru (beforeRender())
V modelu Authorizator bych chtěl zachytávat některé vyjímky metodou flashMessages z presenterů ? Lze to nějako provést? Přes Try catch v before render ?
Editoval Joacim (26. 1. 2016 11:53)
- CZechBoY
- Člen | 3608
Tenhle BasePresenter dědíš určitě i v LoginPresenteru, takže při
startu se ověří uživatel → přesměrování na login, ověří se
uživatel → přesměrování na login → …
Udělej si zvlášť BasePresenter na soukromou a veřejnou část, případně
přepiš startup metodu v LoginPresenter, ale to se hodí asi jen pro
speciální případy a není to moc přehledný.
- Myiyk
- Člen | 321
@Joacim použij $this->isLinkCurrent()
jako ověřování že jsi na té adrese.
Já zabezpečuji presentery tak, že mám BasePresenter
a
SecuredPresenter
, který od něj dědí. Ověřování
přihlášení mám v Secured.
Můj LoginPresenter
dědí od BasePresenter
a tím
se neověřuje přihlášení a nedostanu se do té smyčky.
Editoval Myiyk (26. 1. 2016 12:04)
- Joacim
- Člen | 229
Myiyk napsal(a):
@Joacim použij
$this->isLinkCurrent()
jako ověřování že jsi na té adrese.Já zabezpečuji presentery tak, že mám
BasePresenter
aSecuredPresenter
, který od něj dědí. Ověřování přihlášení mám v Secured.Můj
LoginPresenter
dědí odBasePresenter
a tím se neověřuje přihlášení a nedostanu se do té smyčky.
Paráda to jsem přesně potřeboval
if (!$this->authenticator->isSupportedBrowser() && (!$this->isLinkCurrent("Login:unsupported"))) {
$this->redirect("Login:unsupported");
} elseif ($this->authenticator->isBannedIp()&& (!$this->isLinkCurrent("Login:banned"))) {
$this->redirect("Login:banned");
}
Lze v presenteru:
- přistoupit ke konstantě modelu, který je v presenteru injektován ? $this->authorizator::KONSTANTA ? (chci ji předat do templatu)
- lze předat v modelu presenteru flashMessage ?
Editoval Joacim (26. 1. 2016 12:32)
- David Matějka
- Moderator | 6445
přistoupit ke konstantě modelu, který je v presenteru injektován ? $this->authorizator::KONSTANTA ? (chci ji předat do templatu)
proc nepouzijes IAuthenticator::KONSTANTA
(mimochodem, tridni
property se ti jmenuje authorizator a injectujes tam authenticator, to jsou dve
odlisne veci). jinak ta syntaxe $this->foo::BAR
funguje od php
7, v php 5 kvuli spatnemu parseru to nejde, tam jde jen
napriklad $foo::BAR
lze předat v modelu presenteru flashMessage ?
ne a ani se o to nesnaz, modelova vrstva nema vedet o nejakem presenteru (a jeho flash messages)
- CZechBoY
- Člen | 3608
Udělej to tak, abys nemusel vůbec používat statiku/konstanty na dálku (public).
Jinak ten link tě možná brzo omrzí – třeba až budeš chtít udělat další veřejnou stránku (kontakt třeba).
Pokud si chceš předat důvod, proč je uživatel zabanovanej tak já to řeším tak, že vyhodím vyjímku UserBannedException a v ní je text, který zobrazím ve flashMessage.
- Joacim
- Člen | 229
David Matějka napsal(a):
přistoupit ke konstantě modelu, který je v presenteru injektován ? $this->authorizator::KONSTANTA ? (chci ji předat do templatu)
proc nepouzijes
IAuthenticator::KONSTANTA
(mimochodem, tridni property se ti jmenuje authorizator a injectujes tam authenticator, to jsou dve odlisne veci). jinak ta syntaxe$this->foo::BAR
funguje od php 7, v php 5 kvuli spatnemu parseru to nejde, tam jde jen napriklad$foo::BAR
lze předat v modelu presenteru flashMessage ?
ne a ani se o to nesnaz, modelova vrstva nema vedet o nejakem presenteru (a jeho flash messages)
Ok
Ten authorizator → authenticator mám v kodu dobře, jen jsem dělal pokusy a
v NB jsem si nahrál špatnou historii
- Joacim
- Člen | 229
Joacim napsal(a):
David Matějka napsal(a):
přistoupit ke konstantě modelu, který je v presenteru injektován ? $this->authorizator::KONSTANTA ? (chci ji předat do templatu)
proc nepouzijes
IAuthenticator::KONSTANTA
(mimochodem, tridni property se ti jmenuje authorizator a injectujes tam authenticator, to jsou dve odlisne veci). jinak ta syntaxe$this->foo::BAR
funguje od php 7, v php 5 kvuli spatnemu parseru to nejde, tam jde jen napriklad$foo::BAR
lze předat v modelu presenteru flashMessage ?
ne a ani se o to nesnaz, modelova vrstva nema vedet o nejakem presenteru (a jeho flash messages)
Ok
Ten authorizator → authenticator mám v kodu dobře, jen jsem dělal pokusy a v NB jsem si nahrál špatnou historii
// get credentials
$values = $form->values;
try {
// attempt to login
$this->getUser()->login($values->userName, $values->password);
// successful login
$this->redirect("Homepage:default");
} catch (\Nette\Security\AuthenticationException $e) {
// invalid login
$this->authenticator->recordAttemptToLogin();
$this->flashMessage($e->getMessage(), "danger");
$this->redirect("Login:default");
}
Vrací You cannot serialize or unserialize PDO instances
- Joacim
- Člen | 229
David Matějka napsal(a):
ukaz authenticator
public function authenticate(array $credentials) {
list($username, $password) = $credentials;
$row = $this->database->table('users')->where('userName', $username)->fetch();
if (!$row) {
throw new \Nette\Security\AuthenticationException('User not found', self::IDENTITY_NOT_FOUND);
} else {
$active = $this->database->table('users')->where('userName = ? AND active = 1', $username)->fetch();
if (!$active) {
throw new \Nette\Security\AuthenticationException('User is Inactive', self::IDENTITY_NOT_FOUND);
}
unset($active);
}
if (!\Nette\Security\Passwords::verify($password, $row->password)) {
throw new \Nette\Security\AuthenticationException("Invalid password.", self::INVALID_CREDENTIAL);
}
Předtím jsem měl ještě starou verui kde vše fungovalo, ted to předělávám a nestačím se divit
- Joacim
- Člen | 229
David Matějka napsal(a):
chybi tam ta nejdulezitejsi cast – co vracis
public function authenticate(array $credentials) {
list($username, $password) = $credentials;
$row = $this->database->table('users')->where('userName', $username)->fetch();
if (!$row) {
throw new \Nette\Security\AuthenticationException('User not found', self::IDENTITY_NOT_FOUND);
} else {
$active = $this->database->table('users')->where('userName = ? AND active = 1', $username)->fetch();
if (!$active) {
throw new \Nette\Security\AuthenticationException('User is Inactive', self::IDENTITY_NOT_FOUND);
}
unset($active);
}
if (!\Nette\Security\Passwords::verify($password, $row->password)) {
throw new \Nette\Security\AuthenticationException("Invalid password.", self::INVALID_CREDENTIAL);
}
// load additional information
$userInfo = $this->database->query("SELECT id, role,department_id FROM users WHERE userName = ?", $username)->fetch();
if ($userInfo == null) {
throw new \Nette\Security\AuthenticationException("User not fully configured in system, contact Administrator.", self::IDENTITY_NOT_FOUND);
}
//TODO - logování uživatelů a jejich akcí + update last login
$login_id = $this->addUserLoginInfo($userInfo->id);
// __construct( mixed $id, mixed $roles = NULL, array $data = NULL )
return new Nette\Security\Identity($username, $userInfo->role, array("user_id" => $userInfo->id, "login_id" => $login_id, "department_id" => $userInfo->department_id));
}
- Myiyk
- Člen | 321
@Joacim btw máš 3× select uživatele z databáze, pokaždé ze stejné tabulky. Pokaždé se stejným where.
// 1.
$row = $this->database->table('users')->where('userName', $username)->fetch();
// 2.
$active = $this->database->table('users')->where('userName = ? AND active = 1', $username)->fetch();
// 3.
$userInfo = $this->database->query("SELECT id, role,department_id FROM users WHERE userName = ?", $username)->fetch();
- Joacim
- Člen | 229
Myiyk napsal(a):
@Joacim btw máš 3× select uživatele z databáze, pokaždé ze stejné tabulky. Pokaždé se stejným where.
// 1. $row = $this->database->table('users')->where('userName', $username)->fetch(); // 2. $active = $this->database->table('users')->where('userName = ? AND active = 1', $username)->fetch(); // 3. $userInfo = $this->database->query("SELECT id, role,department_id FROM users WHERE userName = ?", $username)->fetch();
Vím o tom, nejdříve jsem chtěl předělat aplikaci a zítra budu
předělávat Db na Doctrine2
Ještě jedna věc viz. authenticate
throw new \Nette\Security\AuthenticationException('User is Inactive', self::IDENTITY_NOT_FOUND);
jsem nahradil za
$this->recordAttemptToLogin(); // pridat do db zaznam o neuspesnem prihlaseni
$this->lastLoginAttemptException('User not found', self::IDENTITY_NOT_FOUND);
a lastLoginAttemptException je:
private function lastLoginAttemptException($message, $code) {
if ($this->login_attempts == 2) { // Předposlední (druhý pokus) o přihlášení před blokováním
throw new \Nette\Security\AuthenticationException($message . " - Toto je váš poslední pokus.", $code);
} else {
if ($this->login_attempts == 3) { // Blokováno (Toto byl poslední pokus)
$this->login_attempts = 0;
}
throw new \Nette\Security\AuthenticationException($message, $code);
}
}
Chci vědět zda to není napsaný uplně prasácky, nevěděl jsem jak jinak to řešit (potřebuju při předposledním pokusu vyhodit extra hlášku + info co bylo špatně)
throw new – vyhazuji na 4 místech proto jsem napsal tuhle rádoby funkci
Editoval Joacim (26. 1. 2016 16:10)
- Myiyk
- Člen | 321
Nevím odkud bereš hodnotu $this->login_attempts
, ale
v podmínce bych raději použil >= 3
Kdyby se chtěl někdo nabourat, tak může posílat požadavky hodně rychle za sebou, tím je server bude zpracovávat paralelně. A tím by mohl přeskočit tu podmínku.
Ale záleží odkud to číslo bereš.
- Joacim
- Člen | 229
Myiyk napsal(a):
Nevím odkud bereš hodnotu
$this->login_attempts
, ale v podmínce bych raději použil >= 3Kdyby se chtěl někdo nabourat, tak může posílat požadavky hodně rychle za sebou, tím je server bude zpracovávat paralelně. A tím by mohl přeskočit tu podmínku.
Ale záleží odkud to číslo bereš.
to inkrementuji v recordAttemptToLogin, kde se ptám zda-li existuje záznam a pokud ano, tak jej inkrementuji