Autentificare

Nette oferă o modalitate de a programa autentificarea pe paginile noastre, dar nu ne impune nimic. Implementarea depinde în totalitate de noi. Nette include interfața Nette\Security\Authenticator, care necesită doar o singură metodă authenticate, care verifică utilizatorul în orice mod dorim.

Există multe posibilități prin care un utilizator poate fi verificat. Cea mai frecventă metodă de autentificare este prin parolă (utilizatorul furnizează numele său sau e-mailul și parola), dar există și alte metode. Poate cunoașteți butoanele de tip “Conectare cu Facebook” sau autentificarea prin Google/Twitter/GitHub pe unele site-uri. Cu Nette, putem avea orice metodă de autentificare sau le putem combina. Depinde doar de noi.

În mod normal, am scrie propriul nostru authenticator, dar pentru acest blog mic și simplu vom folosi authenticatorul încorporat, care autentifică pe baza parolei și a numelui de utilizator stocate în fișierul de configurare. Este util în scopuri de testare. Adăugăm deci următoarea secțiune security în fișierul de configurare config/common.neon:

security:
	users:
		admin: secret  # utilizator 'admin', parolă 'secret'

Nette va crea automat un serviciu în containerul DI.

Formular de autentificare

Acum avem autentificarea pregătită și trebuie să pregătim interfața utilizator pentru autentificare. Creăm deci un nou presenter numit SignPresenter, care:

  • afișează formularul de autentificare (cu nume de utilizator și parolă)
  • după trimiterea formularului, verifică utilizatorul
  • oferă posibilitatea de deconectare

Începem cu formularul de autentificare. Știm deja cum funcționează formularele în presenteri. Creăm deci presenterul SignPresenter și scriem metoda createComponentSignInForm. Ar trebui să arate cam așa:

<?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', 'Nume utilizator:')
			->setRequired('Vă rugăm să completați numele de utilizator.');

		$form->addPassword('password', 'Parolă:')
			->setRequired('Vă rugăm să completați parola.');

		$form->addSubmit('send', 'Autentificare');

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

Există câmpuri pentru nume de utilizator și parolă.

Șablon

Formularul va fi redat în șablonul in.latte:

{block content}
<h1 n:block=title>Autentificare</h1>

{control signInForm}

Callback de autentificare

Apoi completăm callback-ul pentru autentificarea utilizatorului, care va fi apelat imediat după trimiterea cu succes a formularului.

Callback-ul preia pur și simplu numele de utilizator și parola pe care utilizatorul le-a completat și le transmite authenticatorului. După autentificare, redirecționăm către pagina principală.

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('Nume de utilizator sau parolă incorectă.');
	}
}

Metoda User::login() aruncă o excepție dacă numele de utilizator și parola nu corespund datelor din fișierul de configurare. După cum știm deja, acest lucru poate duce la o pagină roșie de eroare sau, în mod de producție, la un mesaj care informează despre o eroare de server. Nu dorim însă acest lucru. De aceea, prindem această excepție și transmitem un mesaj de eroare frumos și prietenos pentru utilizator în formular.

Odată ce apare o eroare în formular, pagina cu formularul se redesenează și deasupra formularului se afișează un mesaj frumos care informează utilizatorul că a introdus un nume de utilizator sau o parolă greșită.

Securizarea presenterilor

Vom securiza formularul pentru adăugarea și editarea postărilor. Acesta este definit în presenterul EditPresenter. Scopul este de a restricționa accesul la pagină pentru utilizatorii care nu sunt autentificați.

Creăm metoda startup(), care se execută imediat la începutul ciclului de viață al presenterului. Aceasta redirecționează utilizatorii neautentificați către formularul de autentificare.

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

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

Ascunderea linkurilor

Utilizatorul neautorizat nu mai poate vedea pagina create sau edit, dar încă poate vedea linkurile către acestea. Ar trebui să le ascundem și pe acestea. Un astfel de link se află în șablonul app/Presentation/Home/default.latte și ar trebui să fie vizibil doar pentru utilizatorii autentificați.

Îl putem ascunde folosind un n:atribut numit n:if. Dacă această condiție este false, întregul tag <a>, inclusiv conținutul, rămâne ascuns.

<a n:href="Edit:create" n:if="$user->isLoggedIn()">Creează postare</a>

ceea ce este o prescurtare a următoarei notații (a nu se confunda cu tag-if):

{if $user->isLoggedIn()}<a n:href="Edit:create">Creează postare</a>{/if}

În același mod, ascundem și linkul din șablonul app/Presentation/Post/show.latte.

Cum ajungem de fapt la pagina de autentificare? Nu există niciun link care să ducă la ea. Așa că îl vom adăuga în șablonul @layout.latte. Încercați să găsiți un loc potrivit – poate fi aproape oriunde.

...
<ul class="navig">
	<li><a n:href="Home:">Articole</a></li>
	{if $user->isLoggedIn()}
		<li><a n:href="Sign:out">Deconectare</a></li>
	{else}
		<li><a n:href="Sign:in">Autentificare</a></li>
	{/if}
</ul>
...

Dacă utilizatorul nu este autentificat, se afișează linkul “Autentificare”. În caz contrar, se afișează linkul “Deconectare”. Vom adăuga și această acțiune în SignPresenter.

Deoarece redirecționăm imediat utilizatorul după deconectare, nu este nevoie de niciun șablon. Deconectarea arată astfel:

public function actionOut(): void
{
	$this->getUser()->logout();
	$this->flashMessage('Deconectarea a avut succes.');
	$this->redirect('Home:');
}

Se apelează doar metoda logout() și apoi se afișează un mesaj frumos care confirmă deconectarea cu succes.

Rezumat

Avem un link pentru autentificare și, de asemenea, pentru deconectarea utilizatorului. Pentru verificare, am folosit authenticatorul încorporat și avem datele de autentificare în fișierul de configurare, deoarece este o aplicație simplă de test. Am securizat, de asemenea, formularele de editare, astfel încât doar utilizatorii autentificați pot adăuga și edita postări.

Aici puteți citi mai multe despre autentificarea utilizatorilor și Autorizarea permisiunilor.