Authentification
Nette offre un moyen d'implémenter l'authentification sur nos sites, mais n'impose aucune approche particulière.
L'implémentation nous revient entièrement. Nette contient l'interface Nette\Security\Authenticator, qui n'exige
qu'une seule méthode, authenticate, pour vérifier l'utilisateur de la façon que nous choisissons.
Il existe de nombreuses façons d'authentifier un utilisateur. La plus courante est l'authentification par mot de passe (où l'utilisateur fournit son nom ou son e-mail et un mot de passe), mais d'autres existent. Vous connaissez peut-être les boutons “Se connecter avec Facebook” ou la connexion via Google/Twitter/GitHub sur certains sites. Avec Nette, nous pouvons avoir n'importe quelle méthode de connexion, ou même les combiner. La décision nous revient entièrement.
Nous écririons habituellement notre propre authenticator. Pour ce blog tout simple, nous utiliserons cependant l'authenticator
intégré, qui connecte l'utilisateur d'après un nom d'utilisateur et un mot de passe stockés dans le fichier de configuration.
Cela convient à des fins de test. Ajoutons la section security suivante au fichier de configuration
config/common.neon :
security:
users:
admin: secret # utilisateur 'admin', mot de passe 'secret'
Nette crée automatiquement un service pour cet authenticator dans le conteneur DI.
Formulaire de connexion
Maintenant que l'authentification est en place, nous devons créer une interface utilisateur pour la connexion. Créons un
nouveau presenter nommé SignPresenter, qui va :
- afficher un formulaire de connexion (avec les champs nom d'utilisateur et mot de passe)
- authentifier l'utilisateur lors de l'envoi du formulaire
- proposer une possibilité de déconnexion
Commençons par le formulaire de connexion. Nous savons déjà comment fonctionnent les formulaires dans les presenters.
Créons SignPresenter et écrivons la méthode createComponentSignInForm. Elle devrait ressembler à
ceci :
<?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', 'Nom d\'utilisateur :')
->setRequired('Veuillez saisir votre nom d\'utilisateur.');
$form->addPassword('password', 'Mot de passe :')
->setRequired('Veuillez saisir votre mot de passe.');
$form->addSubmit('send', 'Se connecter');
$form->onSuccess[] = $this->signInFormSucceeded(...);
return $form;
}
}
Il y a des champs pour le nom d'utilisateur et le mot de passe.
Template
Le formulaire sera rendu dans le template in.latte :
{block content}
<h1 n:block=title>Connexion</h1>
{control signInForm}
Callback de connexion
Ajoutons ensuite la méthode de rappel qui connecte l'utilisateur, appelée juste après l'envoi réussi du formulaire.
Le callback se contente de prendre le nom d'utilisateur et le mot de passe saisis et de les passer à l'authenticator. Après une connexion réussie, nous redirigeons vers la page d'accueil.
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('Nom d\'utilisateur ou mot de passe incorrect.');
}
}
La méthode User::login() lève une exception si le nom d'utilisateur et le mot de passe ne correspondent pas aux identifiants du fichier de configuration. Comme nous le savons, cela produirait un écran rouge de Tracy ou, en mode production, un message d'erreur du serveur. Nous ne voulons pas cela. Nous attrapons donc l'exception et ajoutons au formulaire un joli message d'erreur compréhensible.
Lorsqu'une erreur de formulaire survient, la page contenant le formulaire est rendue à nouveau et un message apparaît au-dessus du formulaire pour informer l'utilisateur qu'il a saisi un mauvais nom d'utilisateur ou un mauvais mot de passe.
Sécuriser les presenters
Nous allons sécuriser le formulaire d'ajout et d'édition d'articles, défini dans EditPresenter. Le but est
d'empêcher les utilisateurs non connectés d'accéder à la page.
Nous créerons une méthode startup(), qui s'exécute tout au début du cycle de vie du presenter. Cette méthode
redirigera les utilisateurs non connectés vers le formulaire de connexion.
public function startup(): void
{
parent::startup();
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Sign:in');
}
}
Masquer les liens
Un utilisateur non autorisé ne peut plus voir les pages create et edit, mais il voit toujours les liens qui y
mènent. Nous devrions les masquer aussi. L'un de ces liens se trouve dans le template
app/Presentation/Home/default.latte et ne devrait être visible que par les utilisateurs connectés.
Nous pouvons le masquer à l'aide d'un n:attribut appelé n:if. Si la condition est false,
toute la balise <a>, contenu compris, ne sera pas affichée.
<a n:href="Edit:create" n:if="$user->isLoggedIn()">Créer un article</a>
ce qui est un raccourci pour l'écriture suivante (à ne pas confondre avec tag-if) :
{if $user->isLoggedIn()}<a n:href="Edit:create">Créer un article</a>{/if}
Masquez de la même façon le lien d'édition dans le template app/Presentation/Post/show.latte.
Lien de connexion
Comment arriver concrètement à la page de connexion ? Aucun lien n'y mène. Ajoutons-en un au template
@layout.latte. Essayez de trouver un endroit approprié, cela peut être presque n'importe où.
...
<ul class="navig">
<li><a n:href="Home:">Accueil</a></li>
{if $user->isLoggedIn()}
<li><a n:href="Sign:out">Se déconnecter</a></li>
{else}
<li><a n:href="Sign:in">Se connecter</a></li>
{/if}
</ul>
...
Si l'utilisateur n'est pas connecté, le lien “Se connecter” est affiché. Sinon, c'est le lien “Se déconnecter”. Nous
ajouterons aussi cette action à SignPresenter.
Comme nous redirigeons l'utilisateur juste après la déconnexion, aucun template n'est nécessaire. L'action de déconnexion ressemble à ceci :
public function actionOut(): void
{
$this->getUser()->logout();
$this->flashMessage('Vous avez été déconnecté.');
$this->redirect('Home:');
}
Elle se contente d'appeler la méthode logout(), puis affiche un message de confirmation à l'utilisateur.
Résumé
Nous avons des liens pour connecter et déconnecter l'utilisateur. Nous avons utilisé l'authenticator intégré pour l'authentification et les identifiants de connexion se trouvent dans le fichier de configuration, puisqu'il s'agit d'une application de test toute simple. Nous avons aussi sécurisé les formulaires d'édition, afin que seuls les utilisateurs connectés puissent ajouter et modifier des articles.
Vous pouvez en lire davantage ici sur la connexion des utilisateurs et l'autorisation.