Autenticazione

Nette fornisce un modo per programmare l'autenticazione sulle nostre pagine, ma non ci obbliga a nulla. L'implementazione dipende solo da noi. Nette contiene l'interfaccia Nette\Security\Authenticator, che richiede solo un metodo authenticate, che verifica l'utente in qualsiasi modo desideriamo.

Ci sono molte opzioni su come un utente può essere autenticato. Il metodo di autenticazione più comune è tramite password (l'utente fornisce il proprio nome o e-mail e password), ma ci sono anche altri modi. Forse conoscete i pulsanti del tipo “Accedi con Facebook”, o l'accesso tramite Google/Twitter/GitHub su alcuni siti. Con Nette possiamo avere qualsiasi metodo di accesso, o possiamo anche combinarli. Dipende solo da noi.

Normalmente scriveremmo il nostro authenticator, ma per questo semplice piccolo blog useremo l'authenticator integrato, che accede in base a password e nome utente memorizzati nel file di configurazione. È utile per scopi di test. Aggiungiamo quindi la seguente sezione security al file di configurazione config/common.neon:

security:
	users:
		admin: secret  # utente 'admin', password 'secret'

Nette crea automaticamente un servizio nel container DI.

Form di accesso

Ora abbiamo l'autenticazione pronta e dobbiamo preparare l'interfaccia utente per l'accesso. Creiamo quindi un nuovo presenter chiamato SignPresenter, che:

  • visualizzerà il form di accesso (con nome utente e password)
  • dopo l'invio del form, verificherà l'utente
  • fornirà la possibilità di disconnettersi

Iniziamo con il form di accesso. Sappiamo già come funzionano i form nei presenter. Creiamo quindi il presenter SignPresenter e scriviamo il metodo createComponentSignInForm. Dovrebbe assomigliare a qualcosa del genere:

<?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', 'Nome utente:')
			->setRequired('Per favore, inserisci il tuo nome utente.');

		$form->addPassword('password', 'Password:')
			->setRequired('Per favore, inserisci la tua password.');

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

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

Ci sono campi per nome utente e password.

Template

Il form verrà renderizzato nel template in.latte:

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

{control signInForm}

Callback di accesso

Successivamente, aggiungiamo il callback per l'accesso dell'utente, che verrà chiamato subito dopo l'invio riuscito del form.

Il callback prende semplicemente il nome utente e la password che l'utente ha inserito e li passa all'authenticator. Dopo l'accesso, reindirizziamo alla pagina iniziale.

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('Nesprávné přihlašovací jméno nebo heslo.');
	}
}

Il metodo User::login() lancerà un'eccezione se il nome utente e la password non corrispondono ai dati nel file di configurazione. Come già sappiamo, questo può portare a una pagina di errore rossa, o in modalità produzione a un messaggio che informa di un errore del server. Tuttavia, non vogliamo questo. Pertanto, catturiamo questa eccezione e passiamo un messaggio di errore carino e user-friendly al form.

Non appena si verifica un errore nel form, la pagina con il form viene ridisegnata e sopra il form viene visualizzato un messaggio carino che informa l'utente che ha inserito un nome utente o una password errati.

Protezione dei presenter

Proteggiamo il form per l'aggiunta e la modifica dei post. Questo è definito nel presenter EditPresenter. L'obiettivo è impedire l'accesso alla pagina agli utenti che non sono loggati.

Creiamo il metodo startup(), che viene eseguito immediatamente all'inizio del ciclo di vita del presenter. Questo reindirizzerà gli utenti non loggati al form di accesso.

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

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

Un utente non autorizzato non può più vedere la pagina createedit, ma può ancora vedere i link ad esse. Dovremmo nascondere anche questi. Uno di questi link si trova nel template app/Presentation/Home/default.latte e dovrebbe essere visibile solo agli utenti loggati.

Possiamo nasconderlo utilizzando un n:attributo chiamato n:if. Se questa condizione è false, l'intero tag <a>, incluso il contenuto, rimarrà nascosto.

<a n:href="Edit:create" n:if="$user->isLoggedIn()">Crea post</a>

che è l'abbreviazione della seguente notazione (da non confondere con tag-if):

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

Allo stesso modo, nascondiamo anche il link nel template app/Presentation/Post/show.latte.

Come arriviamo effettivamente alla pagina di accesso? Non c'è nessun link che porti ad essa. Quindi aggiungiamolo al template @layout.latte. Provate a trovare un posto adatto – può essere quasi ovunque.

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

Se l'utente non è loggato, verrà visualizzato il link “Accedi”. Altrimenti, verrà visualizzato il link “Esci”. Aggiungiamo anche questa azione a SignPresenter.

Poiché reindirizziamo immediatamente l'utente dopo la disconnessione, non è necessario alcun template. La disconnessione assomiglia a questo:

public function actionOut(): void
{
	$this->getUser()->logout();
	$this->flashMessage('Odhlášení bylo úspěšné.');
	$this->redirect('Home:');
}

Viene semplicemente chiamato il metodo logout() e successivamente viene visualizzato un messaggio carino che conferma la disconnessione riuscita.

Abbiamo un link per l'accesso e anche per la disconnessione dell'utente. Per l'autenticazione abbiamo utilizzato l'authenticator integrato e i dati di accesso li abbiamo nel file di configurazione, poiché si tratta di una semplice applicazione di test. Abbiamo anche protetto i form di modifica, quindi solo gli utenti loggati possono aggiungere e modificare i post.

Qui potete leggere di più sul login degli utenti e sulla Verifica delle autorizzazioni.