Authentifizierung
Nette bietet eine Möglichkeit, die Authentifizierung auf unseren Seiten zu programmieren, zwingt uns aber zu nichts. Die
Implementierung liegt ganz bei uns. Nette enthält das Interface Nette\Security\Authenticator
, das nur eine Methode
authenticate
erfordert, die den Benutzer auf beliebige Weise überprüft.
Es gibt viele Möglichkeiten, wie ein Benutzer authentifiziert werden kann. Die häufigste Methode ist die Authentifizierung per Passwort (der Benutzer gibt seinen Namen oder seine E-Mail-Adresse und sein Passwort an), aber es gibt auch andere Methoden. Vielleicht kennen Sie die Schaltflächen „Mit Facebook anmelden“ oder die Anmeldung über Google/Twitter/GitHub auf einigen Websites. Mit Nette können wir jede beliebige Anmeldemethode verwenden oder sie sogar kombinieren. Es liegt ganz bei uns.
Normalerweise würden wir unseren eigenen Authenticator schreiben, aber für diesen einfachen kleinen Blog verwenden wir den
integrierten Authenticator, der die Anmeldung anhand eines in der Konfigurationsdatei gespeicherten Passworts und Benutzernamens
durchführt. Er eignet sich gut für Testzwecke. Fügen wir also den folgenden security
-Abschnitt zur
Konfigurationsdatei config/common.neon
hinzu:
security:
users:
admin: secret # Benutzer 'admin', Passwort 'secret'
Nette erstellt automatisch einen Dienst im DI-Container.
Anmeldeformular
Nun haben wir die Authentifizierung vorbereitet und müssen die Benutzeroberfläche für die Anmeldung erstellen. Erstellen wir
also einen neuen Presenter namens SignPresenter
, der:
- das Anmeldeformular anzeigt (mit Anmeldenamen und Passwort)
- nach dem Absenden des Formulars den Benutzer authentifiziert
- die Möglichkeit zur Abmeldung bietet
Beginnen wir mit dem Anmeldeformular. Wir wissen bereits, wie Formulare in Presentern funktionieren. Erstellen wir also den
Presenter SignPresenter
und schreiben die Methode createComponentSignInForm
. Sie sollte etwa so
aussehen:
<?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', 'Benutzername:')
->setRequired('Bitte geben Sie Ihren Benutzernamen ein.');
$form->addPassword('password', 'Passwort:')
->setRequired('Bitte geben Sie Ihr Passwort ein.');
$form->addSubmit('send', 'Anmelden');
$form->onSuccess[] = $this->signInFormSucceeded(...);
return $form;
}
}
Es gibt Felder für Benutzername und Passwort.
Template
Das Formular wird im Template in.latte
gerendert:
{block content}
<h1 n:block=title>Anmeldung</h1>
{control signInForm}
Anmelde-Callback
Als Nächstes fügen wir den Callback für die Benutzeranmeldung hinzu, der direkt nach dem erfolgreichen Absenden des Formulars aufgerufen wird.
Der Callback übernimmt lediglich den vom Benutzer eingegebenen Benutzernamen und das Passwort und übergibt sie an den Authenticator. Nach der Anmeldung leiten wir zur Startseite weiter.
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('Falscher Benutzername oder falsches Passwort.');
}
}
Die Methode User::login() löst eine Ausnahme aus, wenn Benutzername und Passwort nicht mit den Angaben in der Konfigurationsdatei übereinstimmen. Wie wir bereits wissen, kann dies zu einer roten Fehlerseite oder im Produktionsmodus zu einer Meldung über einen Serverfehler führen. Das wollen wir jedoch nicht. Daher fangen wir diese Ausnahme ab und übergeben eine schöne, benutzerfreundliche Fehlermeldung an das Formular.
Sobald ein Fehler im Formular auftritt, wird die Seite mit dem Formular neu gezeichnet und über dem Formular wird eine nette Nachricht angezeigt, die den Benutzer darüber informiert, dass er einen falschen Benutzernamen oder ein falsches Passwort eingegeben hat.
Absicherung von Presentern
Wir sichern das Formular zum Hinzufügen und Bearbeiten von Beiträgen ab. Dieses ist im Presenter EditPresenter
definiert. Ziel ist es, Benutzern, die nicht angemeldet sind, den Zugriff auf die Seite zu verwehren.
Wir erstellen die Methode startup()
, die sofort zu Beginn des Lebenszyklus des Presenters ausgeführt
wird. Sie leitet nicht angemeldete Benutzer zum Anmeldeformular weiter.
public function startup(): void
{
parent::startup();
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Sign:in');
}
}
Verbergen von Links
Ein nicht autorisierter Benutzer kann die Seiten create
und edit
nicht mehr sehen, aber er kann immer
noch die Links dorthin sehen. Diese sollten wir ebenfalls verbergen. Ein solcher Link befindet sich im Template
app/Presentation/Home/default.latte
und sollte nur für angemeldete Benutzer sichtbar sein.
Wir können ihn mithilfe des n:Attributs namens n:if
verbergen. Wenn diese Bedingung false
ist, bleibt das gesamte <a>
-Tag einschließlich seines Inhalts verborgen.
<a n:href="Edit:create" n:if="$user->isLoggedIn()">Beitrag erstellen</a>
was eine Abkürzung für die folgende Schreibweise ist (nicht zu verwechseln mit tag-if
):
{if $user->isLoggedIn()}<a n:href="Edit:create">Beitrag erstellen</a>{/if}
Auf die gleiche Weise verbergen wir auch den Link im Template app/Presentation/Post/show.latte
.
Link zur Anmeldung
Wie gelangen wir eigentlich zur Anmeldeseite? Es gibt keinen Link, der dorthin führt. Fügen wir ihn also dem Template
@layout.latte
hinzu. Versuchen Sie, einen geeigneten Platz zu finden – er kann fast überall sein.
...
<ul class="navig">
<li><a n:href="Home:">Artikel</a></li>
{if $user->isLoggedIn()}
<li><a n:href="Sign:out">Abmelden</a></li>
{else}
<li><a n:href="Sign:in">Anmelden</a></li>
{/if}
</ul>
...
Wenn der Benutzer nicht angemeldet ist, wird der Link “Anmelden” angezeigt. Andernfalls wird der Link “Abmelden”
angezeigt. Diese Aktion fügen wir auch dem SignPresenter
hinzu.
Da wir den Benutzer nach der Abmeldung sofort weiterleiten, ist kein Template erforderlich. Die Abmeldung sieht wie folgt aus:
public function actionOut(): void
{
$this->getUser()->logout();
$this->flashMessage('Abmeldung erfolgreich.');
$this->redirect('Home:');
}
Es wird nur die Methode logout()
aufgerufen und anschließend eine nette Nachricht angezeigt, die die erfolgreiche
Abmeldung bestätigt.
Zusammenfassung
Wir haben einen Link zur Anmeldung und auch zur Abmeldung des Benutzers. Zur Authentifizierung haben wir den integrierten Authenticator verwendet und die Anmeldedaten befinden sich in der Konfigurationsdatei, da es sich um eine einfache Testanwendung handelt. Wir haben auch die Bearbeitungsformulare gesichert, sodass nur angemeldete Benutzer Beiträge hinzufügen und bearbeiten können.
Hier können Sie mehr über die Benutzeranmeldung und die Berechtigungsprüfung lesen.