Authentifizierung
Nette stellt Ihnen Richtlinien zur Verfügung, wie Sie die Authentifizierung auf Ihrer Seite programmieren können, zwingt Sie
aber nicht dazu, es auf eine bestimmte Weise zu tun. Die Implementierung ist Ihnen überlassen. Nette hat eine Schnittstelle
Nette\Security\Authenticator
, die Sie zwingt, nur eine einzige Methode namens authenticate
zu
implementieren, die den Benutzer auf beliebige Weise findet.
Es gibt viele Möglichkeiten, wie sich ein Benutzer authentifizieren kann. Die gebräuchlichste Methode ist die passwortbasierte Authentifizierung (der Benutzer gibt seinen Namen oder seine E-Mail-Adresse und ein Passwort an), aber es gibt auch andere Möglichkeiten. Vielleicht kennen Sie die „Login mit Facebook“-Schaltflächen auf vielen Websites, oder Sie melden sich über Google/Twitter/GitHub oder eine andere Website an. Mit Nette können Sie jede beliebige Authentifizierungsmethode verwenden oder sie miteinander kombinieren. Es liegt ganz bei Ihnen.
Normalerweise würden Sie Ihren eigenen Authentifikator schreiben, aber für diesen einfachen kleinen Blog werden wir den
eingebauten Authentifikator verwenden, der sich anhand eines Passworts und eines Benutzernamens authentifiziert, die in einer
Konfigurationsdatei gespeichert sind. Das ist gut für Testzwecke. Wir fügen also den folgenden Sicherheits-Abschnitt in
die config/common.neon
Konfigurationsdatei ein:
security:
users:
admin: secret # user 'admin', password 'secret'
Nette wird automatisch einen Dienst im DI-Container erstellen.
Anmeldeformular
Wir haben nun den Backend-Teil der Authentifizierung fertig und müssen eine Benutzeroberfläche bereitstellen, über die sich der Benutzer anmelden kann. Lassen Sie uns einen neuen Präsentator namens SignPresenter erstellen, der
- ein Anmeldeformular anzeigt (und nach Benutzername und Passwort fragt)
- den Benutzer authentifiziert, wenn das Formular abgeschickt wird
- eine Abmeldefunktion bereitstellt
Lassen Sie uns mit dem Anmeldeformular beginnen. Sie wissen bereits, wie Formulare in einem Presenter funktionieren. Erstellen
Sie die SignPresenter
und die Methode createComponentSignInForm
. Es sollte wie folgt aussehen:
<?php
namespace App\UI\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', 'Username:')
->setRequired('Please enter your username.');
$form->addPassword('password', 'Password:')
->setRequired('Please enter your password.');
$form->addSubmit('send', 'Sign in');
$form->onSuccess[] = $this->signInFormSucceeded(...);
return $form;
}
}
Es gibt eine Eingabe für Benutzernamen und Passwort.
Vorlage
Das Formular wird in der Vorlage gerendert in.latte
{block content}
<h1 n:block=title>Sign in</h1>
{control signInForm}
Login-Handler
Wir fügen auch einen Form Handler für die Anmeldung des Benutzers hinzu, der direkt nach dem Absenden des Formulars aufgerufen wird.
Der Handler nimmt einfach den Benutzernamen und das Passwort, die der Benutzer eingegeben hat, und übergibt sie an den zuvor definierten Authentifikator. Nachdem sich der Benutzer angemeldet hat, leiten wir ihn auf die Homepage um.
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('Incorrect username or password.');
}
}
Die Methode User::login() sollte eine Ausnahme auslösen, wenn der Benutzername oder das Passwort nicht mit den zuvor definierten Werten übereinstimmt. Wie wir bereits wissen, würde dies zu einem roten Tracy-Bildschirm führen, oder, im Produktionsmodus, zu einer Meldung über einen internen Serverfehler. Das würde uns nicht gefallen. Deshalb fangen wir die Ausnahme ab und fügen eine nette und freundliche Fehlermeldung in das Formular ein.
Wenn der Fehler im Formular auftritt, wird die Seite mit dem Formular erneut gerendert, und über dem Formular erscheint eine nette Meldung, die den Benutzer darüber informiert, dass er einen falschen Benutzernamen oder ein falsches Passwort eingegeben hat.
Sicherheit der Präsentatoren
Wir werden ein Formular zum Hinzufügen und Bearbeiten von Beiträgen sichern. Es ist im Präsentator
EditPresenter
definiert. Ziel ist es, zu verhindern, dass nicht angemeldete Benutzer auf die Seite zugreifen.
Wir erstellen eine Methode startup()
, die sofort zu Beginn des Lebenszyklus des Präsentators gestartet wird.
Diese leitet nicht eingeloggte Benutzer zum Anmeldeformular um.
public function startup(): void
{
parent::startup();
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Sign:in');
}
}
Links ausblenden
Ein nicht authentifizierter Benutzer kann weder die Seite Erstellen noch die Seite Bearbeiten sehen, aber er kann
immer noch die Links sehen, die auf sie verweisen. Diese sollten wir ebenfalls ausblenden. Ein solcher Link befindet sich in
app/UI/Home/default.latte
, und er sollte nur sichtbar sein, wenn der Benutzer angemeldet ist.
Wir können ihn mit einem n:Attribut namens n:if
ausblenden. Wenn die darin enthaltene Anweisung
false
lautet, werden der gesamte <a>
Tag und sein Inhalt werden nicht angezeigt:
<a n:href="Edit:create" n:if="$user->isLoggedIn()">Create post</a>
Dies ist eine Abkürzung für (nicht zu verwechseln mit tag-if
):
{if $user->isLoggedIn()}<a n:href="Edit:create">Create post</a>{/if}
Sie sollten den Bearbeitungslink unter app/UI/Post/show.latte
auf ähnliche Weise ausblenden.
Link zum Anmeldeformular
Hey, aber wie kommen wir auf die Anmeldeseite? Es gibt keinen Link, der auf sie verweist. Fügen wir einen in die
@layout.latte
Vorlagendatei ein. Versuchen Sie, einen schönen Platz zu finden, es kann überall sein, wo es Ihnen am
besten gefällt.
...
<ul class="navig">
<li><a n:href="Home:">Home</a></li>
{if $user->isLoggedIn()}
<li><a n:href="Sign:out">Sign out</a></li>
{else}
<li><a n:href="Sign:in">Sign in</a></li>
{/if}
</ul>
...
Wenn der Benutzer noch nicht eingeloggt ist, wird der Link „Anmelden“ angezeigt. Andernfalls zeigen wir den Link „Abmelden“ an. Wir fügen diese Aktion in SignPresenter hinzu.
Die Abmeldeaktion sieht wie folgt aus, und da wir den Benutzer sofort umleiten, ist keine Ansichtsvorlage erforderlich.
public function actionOut(): void
{
$this->getUser()->logout();
$this->flashMessage('You have been signed out.');
$this->redirect('Home:');
}
Sie ruft einfach die Methode logout()
auf und zeigt dann eine nette Nachricht an den Benutzer an.
Zusammenfassung
Wir haben einen Link zum Anmelden und zum Abmelden des Benutzers. Da es sich um eine einfache Testanwendung handelt, haben wir zur Authentifizierung den eingebauten Authentifikator verwendet und die Anmeldedaten in der Konfigurationsdatei hinterlegt. Wir haben auch die Bearbeitungsformulare gesichert, so dass nur angemeldete Benutzer Beiträge hinzufügen und bearbeiten können.
Hier können Sie mehr über Benutzeranmeldung und Autorisierung lesen.