Prihlasovanie – problém s InvalidStateException

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

Ahojte, opäť som tu s ďalším problémom. Tentokrát je problém v prihlasovaní.

Mám takýto UsersModel:

<?php
class UsersModel extends NObject implements IAuthenticator
{

	/**
	 * Performs an authentication
	 * @param  array
	 * @return IIdentity
	 * @throws NAuthenticationException
	 */
	public function authenticate(array $credentials)
    {
        $username = $credentials[self::USERNAME];
        $password = $credentials[self::PASSWORD];

        // přečteme záznam o uživateli z databáze
        $row = dibi::fetch('SELECT username, password FROM user WHERE username=%s', $username);

        if (!$row) { // uživatel nenalezen?
            throw new NAuthenticationException("User '$username' not found.", self::IDENTITY_NOT_FOUND);
        }

        if ($row->password !== $password) { // hesla se neshodují?
            throw new NAuthenticationException("Invalid password.", self::INVALID_CREDENTIAL);
        }

        unset($row->password);
        return new NIdentity($row->username, NULL, $row); // vrátíme identitu
    }
}

Vo widget presentery mam v createComponent funkcii nasledovný kod:

$user = NEnvironment::getUser();

		// přihlášení uživatele
		$login = 'pokus';
		$pass = 'pokus';
		$user->login($login, $pass);

		// je přihlášen?
		echo $user->isLoggedIn() ? 'ano' : 'ne';

		// odhlášení
		$user->logout();

Hádže mi to chybu:

InvalidStateException

Cannot regenerate session ID after HTTP headers have been sent (output started at C:\Program Files (x86)\VertrigoServ\www\team10\trunk\widgetizer\app\temp\c-Nette.Template\_6ff1ba15302d6f56ca37bdc04aa023e8.%40layout.phtml.php:17).

Skúšal som už asi všetko čo som vedel. Nič nepomáha, takže sa obraciam na radu smerom k povolanejším osobám :)

dakota
Člen | 148
+
0
-

j-cup napsal(a):

chybu robíš v:

// je přihlášen?
echo $user->isLoggedIn() ? 'ano' : 'ne';
$user->logout();

posielaš na vystup skôr ako odhlasuješ uživateľa (voláš echo …), t.z. pred odhlásením nesmie byť posielané nič na výstup (rovnako ani pred prihlásením uživateľa)

https://api.nette.org/…ion.php.html#200

$user->login($login, $pass);
$user->logout();

je potrebné volať priamo v presenteri a nie v šablone a po prihlásení alebo odhlásení presmerovať $this->redirect(…).

Editoval dakota (23. 12. 2010 8:39)

westrem
Člen | 398
+
0
-

Ja v tom kode vidim ale aj jednu zavaznu bezpecnostnu chybu a to:

if ($row->password !== $password) { // hesla se neshodují?

Toto implikuje, ze do databazy davas heslo v raw podobe, co je ale hodne spatne. Hesla v databaze by mali byt hashovane a saltovane. Minimalne pouzivaj funkciu hash s algoritmom sha256.

Dalsia vec je new NIdentity($row->username, NULL, $row); – zbytocne tam posielas ten $row kedze je v nom len username.

Posledna vec, ktora ale nie je nutne chybou, len mi nepride ako tradicne riesenie, je robit prihlasenie pri vytvarani nejakej konkretnej komponentny.

Vecsinou sa to robi na sposob, ze si vytvoris SecurePresenter, ktori dedi od BasePresenter a v startup metode sa vykona kontrola na prihlasenie. Samotny login sa potom robi v nejakom AuthPresenter, samozrejme, pokial je toto len ukazka kodu za ucelom zjednodusenia tu na fore, tak ok ;)

j-cup
Člen | 21
+
0
-

Ďakujem všetkým za odpovede a za pomoc. Samozrejme išlo len o skušobnú verziu na overenie toho či tomu rozumiem. V reále budú heslá hashované.
Avšak teraz sa mi objavil iný problém. Aplikoval som riešenie z CD-collection example. Vytvoril si AuthPresenter a DashboardPresenter, vyhodil veci okrem samotného prihlasovania a odhlasovania. Všetko funguje. Teda až na jednu vec.

Teraz môj projekt funguje tak, že volám aj samotný login do hlavného DIVu, kde sa mi zobrazuje obsah stránky. Avšak chcel by som prihlasovanie presunúť do vedľajšieho DIVu. Avšak objavil sa mi problém.

V hlavnom @layout.phtml mam 2 include prikazy:

najskôr volám obsah do hlavného divu:
{include #content}
a kusok nizsie aj do vedlajsieho divu
{include #content2}

ako prvy sa mi otvara Homepage presenter. V jeho template default.phtml mam takyto kod:

{block content}
<div class="content_banner">
  <h1>Prispôsobiteľný widget</h1>
  <div class="content_text">
  <p>...nejaky text...</p>
  </div> <!-- content_text -->
  <div class="cleaner"></div>
{/block}

{block content2}
<b>Ahojkooooo!</b>
<p>*Čaw.*</p>
<h1>{block title}Log in{/block}</h1>
{widget loginForm}
<p>Default login is <i>pokus</i>, with password <i>pokus</i></p>
{/block}

Vypise mi to nasledovnu chybovu hlasku:
**InvalidArgumentException

Component with name ‚loginForm‘ does not exist.
**

Ked odstranim volanie {widget loginForm}

Tak sa mi obsah content2 vykresluje ako ma. Lenze prave do tohoto divu chcem dat formular na prihlasenie, resp. ked bude user prihlaseny, tak tam bude info o tom kto je prihlaseny.

Neviete, kde moze byt chyba? V samotnom formulary asi chyba nebude, pretoze ked som presunul include content do vedlajsieho divu, tak sa tam vsetko vypisovali ako do hlavneho divu. Vopred vdaka za dalsie rady :)

dakota
Člen | 148
+
0
-

Ak chceš zobrazovať loginForm vo viacerých presenteroch umiestni metodu createComponentLoginForm aj obslužné handlery napr. loginFormSubmitted naviazané na loginForm do BasePresenteru (ostatné presentery budú od neho dediť – class SomePresenter extends BasePresenter).

V šablone

{block content2}
{if $user->isLoggedIn()}
	Logged user: {$user->identity->username} // podľa toho ako to maš definované
{else}
	{control loginForm}
{/if}
{/block}

Editoval dakota (28. 12. 2010 14:38)