# current_user_can et capacités : le vrai fondement de la sécurité d’une extension

> Vérifier un rôle plutôt qu'une capacité est l'erreur la plus courante dans les extensions WordPress. Voici comment bien utiliser current_user_can.

- Auteur : Clément Hadrot
- Publié le : 2020-11-19
- Mis à jour le : 2020-11-19
- Catégorie : Sécurité
- URL : https://wpmoderne.dev.wordpress-developpement.fr/securite/current-user-can-capacites/

## L’essentiel

- Un rôle est une étiquette, une capacité est une permission réelle
- current_user_can( 'manage_options' ) est presque toujours préférable à un test de rôle
- add_cap permet de créer des permissions sur mesure sans dupliquer de rôle

Quand j'audite le code d'une extension WordPress, la première chose que je cherche dans les écrans d'administration, c'est la présence et la nature des vérifications de permission. Beaucoup de développeurs, même expérimentés, commettent la même erreur : ils vérifient le rôle de l'utilisateur plutôt que ce qu'il a le droit de faire. La différence semble subtile, elle ne l'est pas.

WordPress distingue deux notions souvent confondues : le **rôle**, une étiquette nommée (administrateur, éditeur, auteur, contributeur, abonné), et la **capacité**, une permission précise (`edit_posts`, `manage_options`, `delete_users`...). Un rôle n'est en réalité qu'un ensemble de capacités regroupées sous un nom pratique. C'est cette distinction qui doit guider chaque vérification de sécurité dans le code d'une extension.

## Pourquoi vérifier un rôle est une mauvaise pratique

Un code qui teste explicitement le rôle ressemble souvent à ceci, et c'est justement ce qu'il faut éviter :

```
// À éviter
$user = wp_get_current_user();
if ( in_array( 'administrator', (array) $user->roles, true ) ) {
    // Action sensible
}
```

Le problème est que les rôles ne sont pas figés. Un site peut très bien avoir un rôle personnalisé « responsable_boutique » sans le mot « administrator » dans son nom, mais avec la capacité `manage_woocommerce`. Un code qui ne teste que la présence du rôle littéral `administrator` ignorera silencieusement tout utilisateur légitime disposant d'un rôle personnalisé équivalent, ou pire, autorisera un rôle mal nommé qui ne devrait pas avoir cet accès.

## La bonne pratique : tester la capacité

La fonction `current_user_can()` doit porter sur une capacité, pas sur un rôle :

```
if ( ! current_user_can( 'manage_options' ) ) {
    wp_die( 'Vous n\'avez pas les droits nécessaires pour effectuer cette action.' );
}
```

Cette approche fonctionne quel que soit le rôle réel de l'utilisateur, et reste correcte même si l'administrateur du site réorganise ses rôles et capacités plus tard. C'est exactement le principe pour lequel ce système a été conçu : découpler la permission de l'étiquette qui la porte.

> L'essentiel à retenir : Un rôle est une étiquette, une capacité est une permission réelle ; current_user_can( 'manage_options' ) est presque toujours préférable à un test de rôle ; add_cap permet de créer des permissions sur mesure sans dupliquer de rôle

## Choisir la bonne capacité selon le contexte

Toutes les actions sensibles ne méritent pas `manage_options`, qui est la capacité la plus large, réservée par défaut aux administrateurs. Voici quelques repères utiles :

| Contexte | Capacité adaptée |
| --- | --- |
| Modifier les réglages généraux du site | manage_options |
| Publier ou modifier un article | edit_posts / publish_posts |
| Modifier un article précis | edit_post (avec l'ID de l'article) |
| Gérer les utilisateurs | edit_users, create_users, delete_users |
| Installer une extension | install_plugins |

Utiliser la capacité la plus précise possible pour chaque action limite l'impact d'une éventuelle mauvaise configuration des rôles sur le site : un éditeur capable de publier des articles ne devrait jamais, par accident de code, se retrouver capable de modifier les réglages globaux du site.

## Créer des capacités personnalisées avec add_cap

Quand une extension a des besoins de permission spécifiques, il est souvent préférable de créer une capacité dédiée plutôt que de réutiliser `manage_options` pour tout. La méthode `add_cap()` d'un objet `WP_Role` permet d'attribuer une capacité personnalisée à un rôle existant :

```
function mon_plugin_ajouter_capacite() {
    $role = get_role( 'administrator' );
    if ( $role ) {
        $role->add_cap( 'gerer_mon_plugin' );
    }
}
register_activation_hook( __FILE__, 'mon_plugin_ajouter_capacite' );
```

Ensuite, dans le code de l'extension, on vérifie cette capacité précise plutôt qu'une capacité générique du cœur de WordPress :

```
if ( current_user_can( 'gerer_mon_plugin' ) ) {
    // Affichage de l'écran de réglages de l'extension
}
```

Cette approche permet à l'administrateur du site de déléguer finement l'accès à l'extension à un rôle personnalisé, sans lui donner accès à tous les réglages globaux du site via `manage_options`.

## Les pièges à connaître

- Oublier de retirer la capacité personnalisée lors de la désinstallation de l'extension, via `remove_cap()` sur le hook de désactivation ou de désinstallation ;
- Vérifier une capacité côté affichage du menu, mais oublier de la revérifier dans le traitement du formulaire ou de la requête AJAX associée, ce qui laisse la porte ouverte à quiconque connaît directement l'URL ;
- Confondre `current_user_can( 'edit_post', $post_id )`, qui vérifie les droits sur un article précis, avec `current_user_can( 'edit_posts' )`, qui vérifie une capacité générale sans lien avec un article donné.

> Je recommande systématiquement de vérifier la capacité à la fois à l'affichage (pour ne pas montrer un bouton inutile) et dans le traitement de l'action elle-même. L'affichage seul ne protège rien : n'importe qui peut envoyer la requête directement sans passer par l'interface.

## En résumé

Vérifier un rôle par son nom est une fausse bonne idée qui casse dès que les rôles du site s'écartent de la configuration par défaut. La bonne pratique consiste à toujours passer par `current_user_can()` avec la capacité la plus précise possible pour l'action concernée, et à créer des capacités personnalisées avec `add_cap()` quand les besoins de l'extension le justifient. C'est un réflexe simple qui évite des failles de contrôle d'accès parmi les plus fréquentes du catalogue WordPress.
