Authentikáció

A Nette módot biztosít az authentikáció programozására az oldalainkon, de semmire sem kényszerít minket. Az implementáció kizárólag rajtunk múlik. A Nette tartalmazza a Nette\Security\Authenticator interfészt, amely csak egyetlen authenticate metódust követel meg, amely a felhasználót bármilyen általunk kívánt módon ellenőrzi.

Számos lehetőség van arra, hogyan lehet egy felhasználót hitelesíteni. A leggyakoribb hitelesítési mód a jelszó használata (a felhasználó megadja a nevét vagy e-mail címét és jelszavát), de vannak más módszerek is. Talán ismeri a “Bejelentkezés Facebookkal” típusú gombokat, vagy a Google/Twitter/GitHub segítségével történő bejelentkezést néhány oldalon. A Nette segítségével bármilyen bejelentkezési módszerünk lehet, vagy akár kombinálhatjuk is őket. Ez csak rajtunk múlik.

Általában saját authentikátort írnánk, de ehhez az egyszerű kis bloghoz a beépített authentikátort fogjuk használni, amely a konfigurációs fájlban tárolt jelszó és felhasználónév alapján jelentkeztet be. Tesztelési célokra jól használható. Adjunk hozzá tehát a következő security szekciót a config/common.neon konfigurációs fájlhoz:

security:
	users:
		admin: secret  # felhasználó 'admin', jelszó 'secret'

A Nette automatikusan létrehoz egy szolgáltatást a DI konténerben.

Bejelentkezési űrlap

Most már készen áll az authentikáció, és elő kell készítenünk a felhasználói felületet a bejelentkezéshez. Hozzunk létre tehát egy új presentert SignPresenter néven, amely:

  • megjeleníti a bejelentkezési űrlapot (felhasználónévvel és jelszóval)
  • az űrlap elküldése után ellenőrzi a felhasználót
  • lehetőséget biztosít a kijelentkezésre

Kezdjük a bejelentkezési űrlappal. Már tudjuk, hogyan működnek az űrlapok a presenterekben. Hozzunk létre tehát egy SignPresenter presentert, és írjuk meg a createComponentSignInForm metódust. Valahogy így kellene kinéznie:

<?php
namespace App\Presentation\Sign;

use Nette;
use Nette\Application\UI\Form;

final class SignPresenter extends Nette\Application\UI\Presenter
{
	protected function createComponentSignInForm(): Form
	{
		$form = new Form;
		$form->addText('username', 'Felhasználónév:')
			->setRequired('Kérjük, töltse ki a felhasználónevét.');

		$form->addPassword('password', 'Jelszó:')
			->setRequired('Kérjük, töltse ki a jelszavát.');

		$form->addSubmit('send', 'Bejelentkezés');

		$form->onSuccess[] = $this->signInFormSucceeded(...);
		return $form;
	}
}

Vannak mezők a felhasználónévhez és a jelszóhoz.

Sablon

Az űrlap az in.latte sablonban fog renderelődni:

{block content}
<h1 n:block=title>Bejelentkezés</h1>

{control signInForm}

Bejelentkezési callback

Ezután hozzáadjuk a felhasználó bejelentkezéséhez szükséges callbacket, amely az űrlap sikeres elküldése után azonnal meghívódik.

A callback csak átveszi a felhasználó által kitöltött felhasználónevet és jelszót, és átadja azokat az authentikátornak. Bejelentkezés után átirányítunk a kezdőoldalra.

private function signInFormSucceeded(Form $form, \stdClass $data): void
{
	try {
		$this->getUser()->login($data->username, $data->password);
		$this->redirect('Home:');

	} catch (Nette\Security\AuthenticationException $e) {
		$form->addError('Helytelen felhasználónév vagy jelszó.');
	}
}

User::login() metódus kivételt dob, ha a felhasználónév és a jelszó nem egyezik a konfigurációs fájlban szereplő adatokkal. Ahogy már tudjuk, ez piros hibaoldalt eredményezhet, vagy éles módban egy szerverhibáról tájékoztató üzenetet. Ezt azonban nem akarjuk. Ezért elkapjuk ezt a kivételt, és egy szép, felhasználóbarát hibaüzenetet adunk át az űrlapnak.

Amint hiba történik az űrlapon, az űrlapot tartalmazó oldal újrarajzolódik, és az űrlap felett megjelenik egy szép üzenet, amely tájékoztatja a felhasználót, hogy rossz felhasználónevet vagy jelszót adott meg.

Presenterek védelme

Biztosítsuk a bejegyzések hozzáadására és szerkesztésére szolgáló űrlapot. Ez az EditPresenter presenterben van definiálva. A cél az, hogy megakadályozzuk a nem bejelentkezett felhasználók hozzáférését az oldalhoz.

Létrehozunk egy startup() metódust, amely azonnal elindul a presenter életciklusának elején. Ez átirányítja a nem bejelentkezett felhasználókat a bejelentkezési űrlapra.

public function startup(): void
{
	parent::startup();

	if (!$this->getUser()->isLoggedIn()) {
		$this->redirect('Sign:in');
	}
}

Linkek elrejtése

Az illetéktelen felhasználó már nem láthatja a create vagy edit oldalt, de továbbra is láthatja a rájuk mutató linkeket. Ezeket is el kellene rejtenünk. Egy ilyen link az app/Presentation/Home/default.latte sablonban található, és csak a bejelentkezett felhasználók láthatják.

Elrejthetjük egy n:attribútum használatával, amelynek neve n:if. Ha ez a feltétel false, az egész <a> tag, beleértve a tartalmát is, rejtve marad.

<a n:href="Edit:create" n:if="$user->isLoggedIn()">Bejegyzés létrehozása</a>

ami a következő jelölés rövidítése (nem összetévesztendő a tag-if-fel):

{if $user->isLoggedIn()}<a n:href="Edit:create">Bejegyzés létrehozása</a>{/if}

Ugyanígy elrejtjük a linket az app/Presentation/Post/show.latte sablonban is.

Hogyan jutunk el valójában a bejelentkezési oldalra? Nincs rá mutató link. Adjunk hozzá egyet az @layout.latte sablonhoz. Próbáljon megfelelő helyet találni – szinte bárhol lehet.

...
<ul class="navig">
	<li><a n:href="Home:">Cikkek</a></li>
	{if $user->isLoggedIn()}
		<li><a n:href="Sign:out">Kijelentkezés</a></li>
	{else}
		<li><a n:href="Sign:in">Bejelentkezés</a></li>
	{/if}
</ul>
...

Ha a felhasználó nincs bejelentkezve, a “Bejelentkezés” link jelenik meg. Ellenkező esetben a “Kijelentkezés” link jelenik meg. Ezt az akciót is hozzáadjuk a SignPresenter-hez.

Mivel a felhasználót kijelentkezés után azonnal átirányítjuk, nincs szükség sablonra. A kijelentkezés így néz ki:

public function actionOut(): void
{
	$this->getUser()->logout();
	$this->flashMessage('A kijelentkezés sikeres volt.');
	$this->redirect('Home:');
}

Csak a logout() metódus hívódik meg, majd megjelenik egy szép üzenet, amely megerősíti a sikeres kijelentkezést.

Összegzés

Van linkünk a bejelentkezéshez és a felhasználó kijelentkezéséhez is. Az ellenőrzéshez a beépített authentikátort használtuk, és a bejelentkezési adatokat a konfigurációs fájlban tároljuk, mivel ez egy egyszerű tesztalkalmazás. Biztosítottuk a szerkesztési űrlapokat is, így csak a bejelentkezett felhasználók adhatnak hozzá és szerkeszthetnek bejegyzéseket.

Itt olvashat többet a felhasználók bejelentkeztetéséről és a jogosultságok ellenőrzéséről.