Sèkun blog


Permissions pour lister ou inspecter un modèle avec wagtail

2023-03-18 dev | tags : python wagtail

Wagtail a un comportement par défaut un peu déconcertant sur les autorisation d'accès aux éléments d'un modèle. Par exemple, considérons un modèle Teacher et sa représentation TeacherAdmin dans la page admin de wagtail.

# fichier models.py
class Teacher(models.Model):
    pass

# fichier wagtail_hooks.py
class TeacherAdmin(ModelAdmin):
    model = models.Teacher

On dispose d'une interface nous permettant d'attribuer des permissions, par défaut add_teacher, change_teacher, delete_teacher et view_teacher sont présentes.

Permissions d'objets: cases à cocher avec «ajouter», «modifier», «supprimer»

Un utilisateur n'ayant pas les droits view_teacher, ne pourra donc pas lister ou inspecter un enseignant dans la page admin. Mais, si une seule autre permission lui est assignée, ce sera le cas.

Cela paraît logique: si un utilisateur peut modifier un enseignant, alors il doit pouvoir les lister ou l'inspecter. Seulement, on peut parfois avoir besoin d'ajouter une permission spéciale, qui ne nécessite pas de lister les enseignants, mais autorise l'utilisateur à réaliser certaines actions (en lui laissant accéder à une vue personnalisée). Dans ce cas, lui donner cette permission aura pour effet de lui permettre de lister tous les enseignants, ce qui n'est pas forcément souhaité.

Si on regarde l'implémentation de user_can_list() ou user_can_inspect_object() dans wagtail, on remarque que la permission est accordée si user_has_any_permissions(), i.e. si l'utilisateur a au moins une autre permission sur le modèle. On va changer ce comportement en définissant une nouvelle classe StrictModelAdmin qui nous convient.

from wagtail.contrib.modeladmin.helpers.permission import PermissionHelper
from wagtail.contrib.modeladmin.options import ModelAdmin

class StrictPermissionHelper(PermissionHelper):
    """
    Ne peut accéder ou lister les éléments modèle que si la permission
    view_<model_name> est spécifiée et pas une autre.

    """

    def user_can_view(self, user):
        perm_codename = self.get_perm_codename("view")
        return self.user_has_specific_permission(user, perm_codename)

    def user_can_list(self, user):
        return self.user_can_view(user)

    def user_can_inspect_obj(self, user, obj):
        return self.inspect_view_enabled and self.user_can_view(user)


class StrictModelAdmin(ModelAdmin):
    permission_helper_class = StrictPermissionHelper

On peut utiliser StrictModelAdmin dans les fichiers wagtail_hooks.py en remplacement de ModelAdmin. Il faudra dès lors obligatoirement cocher la permission view_<model_name> si l'on souhaite qu'un utilisateur fasse des opérations CRUD sur des objets du modèle.

Article publié le 18 mars 2023.