IX. Ajout de l'authentification▲
Attaquons-nous désormais à un aspect important de notre site : l'authentification. Heureusement, Play propose un module pour cela ! Il s'agit du module Secure.
IX-A. Activation du module Secure▲
A l'image du module CRUD, il faut activer le module Secure en modifiant notre fichier /yabe/conf/application.properties, puis redémarrer le serveur :
# Import the secure module
module.secure=${play.path}/modules/secure
Normalement, lors du redémarrage, nous devrions être informé que ce module a été chargé.
Comme précédemment, ce module vient avec une série de routes prédéfinies que nous pouvons activer en éditant le fichier /yabe/conf/routes (nous pourrions bien sûr créer nos propres routes, si cela était nécessaire) :
# Import Secure routes
* / module:secure
IX-B. Protection de l'interface d'administration▲
En réalité, ce module propose un contrôleur controllers.Secure qui déclare tous les intercepteurs requis. Nous pourrions étendre cette classe Java, mais nous serions alors confrontés à la limitation du simple héritage de Java.
Ainsi, au lieu d'hériter directement de ce contrôleur, nous pouvons annoter notre contrôleur d'administration avec @With, qui indiquera à Play d'invoquer également les intercepteurs adéquats :
package
controllers;
import
play.*;
import
play.mvc.*;
@With
(
Secure.class
)
public
class
Posts extends
CRUD {
}
Nous modifions de la même façon les classes Comment, User et Tag.
Si nous souhaitons accéder à la page d'administration, nous arrivons en réalité sur une page de connexion :
Pour l'heure, il suffit de renseigner n'importe quel couple login et mot de passe pour pouvoir passer cet écran.
IX-C. Configuration du processus d'authentification▲
Notre application doit disposer d'une instance du contrôleur controllers.Secure.Security afin de nous permettre de configurer le processus d'authentification. C'est grâce à cette implémentation que nous pourrons spécifier la manière exacte dont les utilisateurs devront s'authentifier.
Créons un fichier /yabe/controllers/Security.java et surchargeons la méthode authentify() :
package
controllers;
import
models.*;
public
class
Security extends
Secure.Security {
static
boolean
authentify
(
String username, String password) {
return
true
;
}
}
Etant donné que nous disposons déjà d'un objet User, il est simple de créer une version fonctionnelle de cette méthode :
static
boolean
authentify
(
String username, String password) {
return
User.connect
(
username, password) !=
null
;
}
Maintenant, rendons-nous à l'adresse http://localhost:9000/logout pour se déconnecter, et réessayons de se connecter en utilisant cette fois-ci un utilisateur existant dans le fichier data.yml, tel que bob@gmail.com / secret.
IX-D. Refactorisation de l'interface d'administration▲
Nous avions construit notre interface d'administration en nous appuyant sur le module CRUD. Toutefois, cela s'intègre assez mal avec l'aspect visuel du reste du site. Nous allons donc travailler sur une nouvelle interface d'administration. Cette nouvelle mouture permettra à chaque auteur d'avoir accès à ses propres billets. Toutefois, nous conserverons l'administration basée sur le module CRUD pour les "super administrateurs".
Créons un nouveau contrôleur qui gèrera la partie administration :
package
controllers;
import
play.*;
import
play.mvc.*;
import
java.util.*;
import
models.*;
@With
(
Secure.class
)
public
class
Admin extends
Controller {
@Before
static
void
setConnectedUser
(
) {
if
(
Security.isConnected
(
)) {
User user =
User.find
(
"byEmail"
, Security.connected
(
)).first
(
);
renderArgs.put
(
"user"
, user.fullname);
}
}
public
static
void
index
(
) {
render
(
);
}
}
Refactorisons les routes du fichier /yabe/conf/routes :
# Administration
GET /admin/? Admin.index
* /admin module:crud
Maintenant, lions le texte "Se connecter pour écrire quelque chose" (Log in to write something) situé dans le fichier /yabe/app/views/main.html à ce contrôleur :
...
<ul id
=
"tools"
>
<li>
<a href
=
"@{Admin.index()}"
>
Log in to write something</a>
</li>
</ul>
...
La dernière étape est de créer le template /yabe/app/views/Admin/index.html, en commençant par quelque chose de simple :
Welcome ${user}!
Revenons sur la page d'accueil de notre blog, et cliquons sur ce fameux lien. Si tout s'est bien passé, nous devrions être redirigés vers la nouvelle page d'administration :
C'est un bon début. Comme nous souhaitons disposer de plusieurs pages dans l'interface d'administration, nous allons créer un super template. Choisissons le fichier /yabe/app/views/admin.html pour l'y accueillir :
<!
DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<html xmlns
=
"http://www.w3.org/1999/xhtml"
xml
:
lang
=
"en"
lang
=
"en"
>
<head>
<title>Administration</title>
<meta http-equiv
=
"Content-Type"
content
=
"text/html; charset=utf-8"
/>
#{get 'moreStyles' /}
<link rel
=
"stylesheet"
type
=
"text/css"
media
=
"screen"
href
=
"@{'/public/stylesheets/main.css'}"
/>
<link rel
=
"shortcut icon"
type
=
"image/png"
href
=
"@{'/public/images/favicon.png'}"
/>
<script src
=
"@{'/public/javascripts/jquery-1.3.2.min.js'}"
></script>
<script src
=
"@{'/public/javascripts/jquery.tools.min.js'}"
></script>
</head>
<body id
=
"admin"
>
<div id
=
"header"
>
<div id
=
"logo"
>
yabe. <span>administration</span>
</div>
<ul id
=
"tools"
>
<li>
<a href
=
"@{Secure.logout()}"
>
Log out</a>
</li>
</ul>
</div>
<div id
=
"main"
>
#{doLayout /}
</div>
<p id
=
"footer"
>
Yabe is a (not so) powerful blog engine built with the
<a href
=
"http://www.playframework.org"
>
play framework</a>
as a tutorial application.
</p>
</body>
</html>
Vous pourrez constater que cela est assez proche de ce que nous avons déjà fait pour la page de garde de notre blog. Nous avons changé le lien de connexion par un lien de déconnexion, qui appelle l'action du contrôleur Secure offert par le module de sécurité.
Faisons désormais usage de ce nouveau template dans le fichier /yabe/app/views/Admin/index.html :
#{extends 'admin.html' /}
Welcome ${user}!
Rafraichissons la page :
Si nous nous déconnectons, nous sommes redirigés vers l'écran de connexion :
C'est là la manière classique utilisée par le module de sécurité pour gérer les événements de déconnexion. Cela reste configurable très simplement en surchargeant la méthode onDisconnected() :
static
void
onDisconnected
(
) {
Application.index
(
);
}
Nous pouvons procéder de même avec l'événement onAuthenticated() :
static
void
onAuthenticated
(
) {
Admin.index
(
);
}
IX-E. Ajout des rôles▲
Concrètement, nous avons besoin de deux types d'interface d'administration : la première permettant l'écriture de billet, la seconde pour les super administrateurs. Nous avions ajouté dans la classe User une méthode isAdmin() qui indique justement si cet utilisateur dispose des droits d'administration.
Le module de sécurité offre non seulement le mécanisme d'authentification, mais également la gestion des autorisations. Cela s'appelle les profils. Pour créer un profile administrateur, nous avons juste à surcharger la méthode check() dans la classe controllers.Security :
static
boolean
check
(
String profile) {
if
(
"admin"
.equals
(
profile)) {
return
User.find
(
"byEmail"
, connected
(
)).<
User>
first
(
).isAdmin;
}
return
false
;
}
Nous pouvons dès à présent créer un menu dans l'interface d'administration qui dépendra du profil. Modifions le fichier /yabe/view/main.html pour y ajouter un menu en haut :
...
<div id
=
"main"
>
<ul id
=
"adminMenu"
>
<li class
=
"${request.controller == 'Admin' ? 'selected' : ''}"
>
<a href
=
"@{Admin.index()}"
>
My posts</a>
</li>
#{secure.check 'admin'}
<li class
=
"${request.controller == 'Posts' ? 'selected' : ''}"
>
<a href
=
"@{Posts.list()}"
>
Posts</a>
</li>
<li class
=
"${request.controller == 'Tags' ? 'selected' : ''}"
>
<a href
=
"@{Tags.list()}"
>
Tags</a>
</li>
<li class
=
"${request.controller == 'Comments' ? 'selected' : ''}"
>
<a href
=
"@{Comments.list()}"
>
Comments</a>
</li>
<li class
=
"${request.controller == 'Users' ? 'selected' : ''}"
>
<a href
=
"@{Users.list()}"
>
Users</a>
</li>
#{/secure.check}
</ul>
#{doLayout /}
</div>
...
Remarquez comment nous avons utilisé la balise #{secure.check /} pour afficher les options spécifiques aux administrateurs.
Cela n'est toutefois pas suffisant pour protéger la partie CRUD. Si un utilisateur connaît la bonne URL, il pourra y accéder ! Nous devons ainsi protéger les contrôleurs de la même façon. Cela se fait très simplement, grâce à l'annotation @Check. Ainsi, pour le contrôleur Post :
package
controllers;
import
play.*;
import
play.mvc.*;
@Check
(
"admin"
)
@With
(
Secure.class
)
public
class
Posts extends
CRUD {
}
Procédons de même pour les contrôleurs Tags, Comments et Users. Déconnectons-nous, puis essayons de nous connecter avec un utilisateur simple, par exemple jeff@gmail.com / secret. Normalement, nous ne devons pas voir le menu des administrateurs. De plus, une tentative d'accès direct à l'adresse http://localhost:9000/admin/users devrait nous retourner une erreur 403 (accès refusé) :
IX-F. Configurer la mise en page du CRUD▲
Lorsque nous accédons à la partie CRUD de l'interface d'administration, nous perdons la mise en page de cette dernière. Cela est dû au fait que le module CRUD propose sa propre mise en page. Bien sûr, nous pouvons la surcharger. Commençons par lancer cette commande :
> play crud:ov --layout
Cela nous crée un fichier /yabe/app/views/CRUD/layout.html. Remplaçons son contenu pour améliorer son intégration au reste de l'application :
#{extends 'admin.html' /}
#{set 'moreStyles'}
<link rel
=
"stylesheet"
type
=
"text/css"
media
=
"screen"
href
=
"@{'/public/stylesheets/crud.css'}"
/>
#{/set}
<div id
=
"crud"
>
#{if flash.success}
<div class
=
"crudFlash flashSuccess"
>
${flash.success}
</div>
#{/if}
#{if flash.error || error}
<div class
=
"crudFlash flashError"
>
${error ?: flash.error}
</div>
#{/if}
<div id
=
"crudContent"
>
#{doLayout /}
</div>
</div>
Nous réutilisons le fichier crud.css et l'incluons dans le admin.html en utilisant les mécanismes de get et set des templates. Maintenant, si nous retournons sur les pages du CRUD, nous devrions constater une amélioration de leur intégration :
IX-G. Style de l'écran de connexion▲
Maintenant que notre interface d'administration est cohérente avec le reste de l'application, intéressons-nous à l'écran de connexion. Comme toujours, cet écran est configurable. Lançons la commande suivante :
> play secure:ov --css
Nous allons juste conserver le fichier CSS dans son état, mais avant cela, nous importons notre propre CSS (main.css). Ajoutons donc la ligne suivante dans /yabe/public/stylesheets/secure.css :
@import
url(
main.css)
;
...
Paramétrons finalement les messages de cet écran en ajoutant au fichier /yabe/conf/messages les lignes suivantes :
secure.username=Your email:
secure.password=Your password:
secure.signin=Log in now