Grails – épisode 4 – Utilisation des plugins
Résumé de l’épisode précédent …
L’application est déjà fonctionnelle et entièrement utilisable ! Il est possible de gérer assez facilement sa collection d’album en incluant rapidement des chansons préalablement créés. Mais en l’état actuel, rien n’est sécurisé …
Ajout de la sécurité
Pour ajouter la notion de sécurité sur notre application, nous allons piocher dans le formidable réservoir à plugins de Grails. Vous pouvez consulter la liste des plugins disponibles en tapant cette commande:
1 | grails list-plugins |
Qu’est ce qu’un plugin Grails ?
Un plugin Grails est une archive au format zip contenant des classes, des taglibs, de nouvelles commandes, et tout un tas d’autres choses diverses et variées (c’est selon le plugin). Lors de l’installation d’un plugin, Grails rapatrie cette archive sur votre machine (en local) et inclut son contenu dans votre application. En quelques secondes, il est possible par exemple:
- de rajouter la sécurité (il ne restera plus qu’à la configurer)
- d’intégrer de nouveaux composants Javascripts : utile pour l’IHM
- d’intégrer un moteur recherche full-text
- de rajouter l’accès au protocole XMPP (Jabber)
- et encore bien d’autres choses … je vous laisse consulter la liste
Installation du plugin de sécurité
Pour installer le plugin de sécurité, tapez cette commande:
1 | grails install-plugin acegi |
Grails installe automatiquement la dernière version disponible sur le dépôt Grails.org.
Le plugin “acegi” ajoute trois nouvelles commandes à l’écosystème de Grails:
- grails create-auth-domains
- grails generate-manager
- grails generate-registration
Nous n’utiliserons que la première. Si vous souhaitez en savoir plus sur les deux autres, je vous invite à consulter la documentation en ligne du plugin: http://grails.org/plugin/acegi
Configuration de la sécurité
Pour commencer, nous allons installer les différents objets du domaine utiles pour la gestion des utilisateurs. Pour cela, nous allons utiliser une des commandes fournies par le plugin:
1 | grails create-auth-domains com.excilys.grails.AlbumUser com.excilys.grails.Role Requestmap |
Cette commande prend en paramètre:
- le nom de la classe utilisateur à générer (évitez d’utiliser User car “user” est un mot réservé pour PostGreSQL)
- le nom de la classe rôle à générer
- le nom de la classe requestmap à générer
Vous remarquerez que seule la classe RequestMap n’est pas préfixée d’un nom de package. C’est parce que cette classe ne nous servira à rien: nous allons simplement la supprimer.
1 | rm grails-app/domain/Requestmap.groovy |
Jetez également un œil sur votre arborescence de fichiers:
- deux nouveaux contrôleurs ont été ajoutés : LoginController et LogoutController
- de nouvelles vues ont été ajoutées incluant la vue de login
Maintenant, éditez le fichier grails-app/conf/SecurityConfig.groovy:
1
2
3
4
5
6
7 security {
active = true
useRequestMapDomainClass = false
loginUserDomainClass = "com.excilys.grails.AlbumUser"
authorityDomainClass = "com.excilys.grails.Role"
useControllerAnnotations = true
}
Plusieurs paramètres importants sont définis dans ce fichier:
- active : cette option est assez explicite, elle permet d’indiquer si la sécurité est active … ou pas
- useRequestMapDomainClass : puisque les Requestmap ne seront pas utilisées, on les désactive
- loginUserDomainClass et authorityDomainClass permettent d’identifier les classes utilisées pour la sécurité (utilisateur et rôle)
- useControllerAnnotations : active le mode de sécurité par annotation
Notez bien qu’il existe plusieurs façons de configurer le mode de sécurité:
- par annotations, c’est celle que je vais vous montrer
- statique, toutes les URL à protéger sont définis dans le fichier SecurityConfig.groovy
- stockée en base, les URL sont stockées en base: ce sont les Requestmap
Ok ! La sécurité est installée et quasiment configurée. Lançons notre application:
1 | grails run-app |
Rendez-vous sur la page d’accueil: http://localhost:8080/albums/ Maintenant, verrouillons …
Verrouillage
Nous voulons que l’interface de création des albums et des chansons soit protégée et réservée aux utilisateurs disposant du rôle d’administration. Le même niveau de sécurité est demandé sur les actions de mise à jour et de suppression. Seules les actions “list” et “show” pourront être publiques (et plus tard l’action “rss”).
Éditez le contrôleur Album ainsi que le contrôleur Song et ajoutez cette annotation en import:
1 | import org.codehaus.groovy.grails.plugins.springsecurity.Secured; |
Maintenant, pour chacune des actions que nous souhaitons protéger, il suffira d’annoter l’action avec:
1 | @Secured(['ROLE_ADMIN']) |
Par exemple, l’action “create” sur le contrôleur Album:
1
2
3
4
5
6
7
8
9 @Secured(['ROLE_ADMIN'])
def create = {
def albumInstance = new Album()
albumInstance.properties = params
def availableSongs = Song.findAllByAlbumIsNull()
return ['albumInstance':albumInstance, 'availableSongs':availableSongs]
}
Essayez maintenant d’accéder à l’écran de création d’un album : http://localhost:8080/albums/album/create
Voila un bel écran de login mais impossible de se connecter, il n’y a aucun utilisateur en base ! Vous pouvez décider de créer l’interface d’enregistrement (en utilisant une des commandes du plugin : grails generate-registration) ou bien le rajouter à la main ou encore le configurer dans le BootStrap …
Le BootStrap ? késako ?! Ce fichier se situe dans grails-app/conf/. C’est un script Groovy qui s’exécute au moment de l’initialisation ou de la destruction de l’application. Dans ce script vous pouvez décider de créer un ou plusieurs utilisateurs (en faisant quelques vérifications). Exemple:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import com.excilys.grails.*
class BootStrap {
def init = { servletContext ->
def myUser = AlbumUser.findByUsername ("grails")
if (!myUser){
// l'utilisateur n'existe pas
// 0b9c2625dc21ef05f6ad4ddf47c5f203837aa32c = toto (SHA1)
myUser = new AlbumUser ( username:'grails', passwd:'0b9c2625dc21ef05f6ad4ddf47c5f203837aa32c',
userRealName:'Grails Rocks', email:'grails@excilys.com', enabled:true).save()
// Ajout du rôle admin pour cet utilisateur
def role = Role.findByAuthority ("ROLE_ADMIN")
if (!role){
role = new Role (authority:'ROLE_ADMIN', description:'Administrateur').save(flush:true)
}
// une autre méthode dynamique de Grails, elle permet d'ajouter un
// objet dans une collection persistée. La collection s'appelle "authorities" et est typée 'Role' dans l'objet myUser
myUser.addToAuthorities (role)
}
}
def destroy = {
}
}
Avec ce script, à chaque fois que l’application démarre:
- on vérifie qu’un utilisateur nommé “grails” existe
- s’il n’existe pas on le crée, s’il existe on ne fait rien
- dans le cas où l’utilisateur est fraîchement créé, on lui attribue un rôle nommé ROLE_ADMIN
- ce rôle est immédiatement créé si non-existant en base
Vous pouvez maintenant vous connecter en utilisant le login grails (mot de passe, ‘toto’).
Ajout des flux RSS
Maintenant que nous savons utiliser les plugins, nous allons les utiliser ! Prenons un autre exemple, le cas des flux RSS:
1 | grails install-plugin feeds |
Le plugin “feeds” permet d’intégrer l’API Rome à votre application : inclusion des dépendances, mise à disposition de méthodes facilitant l’utilisation de la librairie et taglibs.
Nous allons créer deux flux RSS:
- sur les albums, le flux récupèrera les 10 derniers albums par ordre de publication
- sur les chansons, le flux récupèrera les 25 dernières chansons
Le flux album
Editez le controller Album et ajoutez cette action:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 def rss = {
// Chargement des albums
def albums = Album.list(max:10, sort:'dateCreated', order:'desc')
// la méthode render est disponible sur tous les contrôleurs
render(feedType:"rss", feedVersion:"2.0") {
title = "Flux RSS sur les albums" // le titre du flux
link = createLink (controller:'album', action:'list', absolute:true) // le lien pour aller sur la liste des albums
description = "Flux RSS sur les albums" // la description globale du flux
albums.each() { album -> // pour chaque album dans la liste
entry(album.name) { // créer une entrée
link = createLink(controller:'album', action:'show', id:album.id, absolute:true)
// le lien de l'entrée (vers le site en absolu)
album.description // et le corps de l'entrée
}
}
}
}
Lancez l’application:
1 | grails run-app |
Et admirez le résultat
http://localhost:8080/albums/album/rss
Le flux chanson
Le flux chanson est implémenté de la même façon que celui des albums. Je vous laisse regarder le code source de l’épisode. (cf: ressources)
D’autres plugins …
Bien évidemment le but n’est pas d’énumérer tous les plugins existants. D’autant plus que des plugins que je considère intéressants ne le seront peut-être pas pour vous. Néanmoins, voici une petite liste de plugins que j’ai déjà eu l’occasion d’utiliser (avec plus ou moins de succès):
- le plugin “searchable”, ajoute la fonctionnalité de recherche full-text en incluant les technologies Compass et Lucène
- le plugin “auditable”, permet de faire de l’audit sur chacune des opération CRUD des objets du domaine
- le plugin “xmpp”, pour envoyer des messages Jabber
- le plugin “mail”, pour envoyer des mails (Javamail)
- le plugin “quartz”, utile pour intégrer le framework Quartz (déclenchement de Job à intervalle régulier)
- le plugin “jquery”, pour intégrer JQuery dans votre application
- et bien d’autres encore (ofchart pour des graphiques en Flash, jcaptcha pour une gestion simple de captcha, …)
Il est important de préciser qu’il faut rester prudent vis-à-vis des plugins : ils ne sont pas toujours adaptés dans le cadre d’un projet professionnel. Et dans certains cas, ils posent plus de problèmes qu’ils n’en résolvent… Un seul conseil (valable en soi pour n’importe quelle technologie) : testez le plugin avant de l’intégrer dans votre projet. Utilisez-le et repérez ces limitations. Un plugin peut-être désinstallé avec cette commande :
1 | grails uninstall-plugin PLUGIN_NAME |
Gardez bien à l’esprit que le code correspondant à l’intégration du plugin supprimé ne le sera pas (les taglibs dans les vues, les actions dans les contrôleurs, …). Supprimer un plugin bien implenté dans votre application peut donc présenter un coût non négligeable. Les plugins sont à utiliser avec parcimonie donc…
La suite au prochain numéro !!
Dans le prochain numéro nous verrons comment utiliser notre nouvelle application: le packaging et déploiement en prod, la configuration avancée, la notion d’environnement…
Ressources
Code source de l’épisode: albums_episode4.zip
Tag sur le SVN Google Code : http://excilys.googlecode.com/svn/projects/grails-albums/tags/grails-albums_article_4/
Grails et les plugins: http://grails.org/plugin/home
Documentation du plugin acegi: http://grails.org/plugin/acegi
Documentation du plugin feeds: http://grails.org/plugin/feeds


Tout continue de rouler parfaitement
à noter quand même la modification à faire dans le Album.groovy de grails-app/domain pour que “sort:dateCreated” ne pose pas problème :
//Date publication
Date dateCreated // date autogérée par Grails
et donc, comme précisé en commentaire, le dateCreated qui fait partie de l’Automatic timestamping de GORM : http://www.grails.org/GORM+-+Events