Personnalisation des menus de permissions utilisateur dans Simple UI pour Django

Lors de l'intégration de Simple UI dans Django, il est fréquent de devoir adapter les menus affichés en fonction des rôles et permissions des utilisateurs. Cela permet de masquer les éléments non autorisés, comme les liens ou boutons, en se basant sur une structure de permissions personnalisée.

Définition des modèles

Pour gérer les utilisateurs et les menus, nous définissons d'abord un modèle d'utilisateur personnalisé et un modèle de menu. Notez que cette approche est spécifique et nécessite des ajustements en cas de modification.


class UtilisateurPersonnalise(AbstractBaseUser, PermissionsMixin):
    courriel = models.EmailField(verbose_name='Adresse e-mail', max_length=255, unique=True)
    telephone = models.CharField('Numéro de téléphone', max_length=20)
    date_creation = models.DateTimeField('Date de création', default=timezone.now)
    nom_complet = models.CharField('Nom complet', max_length=20)
    est_actif = models.BooleanField(default=True)
    est_admin = models.BooleanField('Accès à l\'administration', default=False)  # Contrôle l'accès au backend

    objects = GestionnaireUtilisateur()

    USERNAME_FIELD = 'courriel'
    REQUIRED_FIELDS = ['nom_complet', 'telephone']

    def __str__(self):
        return self.nom_complet

    @property
    def est_personnel(self):
        return self.est_admin

    class Meta:
        verbose_name = 'Utilisateur'
        verbose_name_plural = 'Utilisateurs'
        permissions = [
            ("afficher_utilisateur", "Peut afficher la liste des utilisateurs"),
            ("bloquer_utilisateur", "Peut désactiver un compte utilisateur"),
        ]


class ElementNavigation(models.Model):
    TYPE_CHOICES = (
        ('api', 'Point d\'accès'),
        ('menu', 'Menu')
    )
    intitule = models.CharField(max_length=30, unique=True, db_index=True, verbose_name="Nom de l'élément")
    icone = models.CharField(max_length=50, null=True, blank=True, verbose_name="Icône")
    lien = models.CharField(max_length=255, null=True, blank=True, verbose_name="URL")
    type_element = models.CharField(max_length=30, null=True, blank=True, db_index=True, choices=TYPE_CHOICES,
                                     verbose_name='Type')
    visible = models.BooleanField(default=True, db_index=True, verbose_name="Visible dans le menu")
    ordre = models.IntegerField(null=True, blank=True, db_index=True, verbose_name="Ordre de tri")
    parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name="Élément parent")

    def __str__(self):
        return self.intitule

    class Meta:
        verbose_name = 'Élément de navigation'
        verbose_name_plural = 'Éléments de navigation'
        ordering = ['id']

Configuration de Simple UI

Simple UI utilise une configuration statique ou dynamique pour les menus. Ici, nous désactivons la génération automatique pour utiliser un menu personnalisé basé sur les permissions.


SIMPLEUI_CONFIG = {
    'dynamic': False,
    'menus': [],
}

Middleware pour le contrôle dynamique des menus

Un middleware inetrcepte chaque requête pour construire la liste des menus autorisés en fonction des permissions de l'utilisateur connecté. Les chemins d'accès sont générés à partir des permissions, en supposant une convention de nommage cohérente dans les modèles Django.


class MenuPermissionMiddleware(MiddlewareMixin):
    """
    Génère dynamiquement les menus visibles selon les permissions utilisateur.
    """
    def process_request(self, request):
        utilisateur = request.user
        permissions = utilisateur.get_all_permissions()
        chemins_autorises = set()  # Format: /admin/app_label/model_name/

        for perm in permissions:
            parties = perm.split('.')
            if len(parties) >= 2:
                app_label = parties[0]
                module_name = parties[1].split('_')[-1]
                chemin = f'/admin/{app_label}/{module_name}/'
                chemins_autorises.add(chemin)

        from .models import ElementNavigation  # Import local pour éviter les imports circulaires
        menus_racines = ElementNavigation.objects.filter(
            type_element='menu', visible=True
        ).order_by('ordre')

        menu_complet = []
        for racine in menus_racines:
            sous_elements = racine.elementnavigation_set.filter(
                visible=True
            ).order_by('ordre')
            entree_menu = {
                'name': racine.intitule,
                'icon': racine.icone,
                'models': []
            }
            for sous_elem in sous_elements:
                if sous_elem.lien in chemins_autorises:
                    entree_menu['models'].append({
                        'name': sous_elem.intitule,
                        'icon': sous_elem.icone,
                        'url': sous_elem.lien
                    })
            if entree_menu['models']:
                menu_complet.append(entree_menu)

        settings.SIMPLEUI_CONFIG['menus'] = menu_complet
        return None

Gestion des menus dans l'administration

Les modèles définis peuvent être enregistrés dans l'interface d'administration Django pour permettre la création et la modification des éléments de navigation via l'admin.

Étiquettes: Django simpleui permissions middleware custom-menus

Publié le 11 juin à 03h59