Tato stránka obsahuje smyčku přesměrování + flashMessages v Modelu?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Joacim
Člen | 229
+
0
-

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)

Myiyk
Člen | 321
+
0
-

Musíš ošetřit, aby jsi nepřesměroval, pokud již jsi na té adrese.

David Matějka
Moderator | 6445
+
+1
-

nededi ti LoginPresenter od BasePresenteru?

CZechBoY
Člen | 3608
+
0
-

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ý.

Joacim
Člen | 229
+
0
-

Myiyk napsal(a):

Musíš ošetřit, aby jsi nepřesměroval, pokud již jsi na té adrese.

$this->getName() !== „Login“) lze si zavolat i template toho presenteru ? např: „Login:default“ ?

V přesměrování se vždy zacyklím :D

Editoval Joacim (26. 1. 2016 11:57)

Myiyk
Člen | 321
+
0
-

@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
+
0
-

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 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.

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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

David Matějka
Moderator | 6445
+
0
-

ukaz authenticator

Joacim
Člen | 229
+
0
-

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

David Matějka
Moderator | 6445
+
0
-

chybi tam ta nejdulezitejsi cast – co vracis

Joacim
Člen | 229
+
0
-

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));
}
David Matějka
Moderator | 6445
+
+1
-

co obsahuje login_id? kdyz si to dumpnes

Joacim
Člen | 229
+
0
-

David Matějka napsal(a):

co obsahuje login_id? kdyz si to dumpnes

Měla vracet lastId, jen jak jsem to přepisoval zapomněl jsem na ->id u proměnné

Myiyk
Člen | 321
+
0
-

@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
+
0
-

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
+
0
-

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
+
0
-

Myiyk napsal(a):

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š.

to inkrementuji v recordAttemptToLogin, kde se ptám zda-li existuje záznam a pokud ano, tak jej inkrementuji