Gérer les autorisations des espaces membres

Lorsque l’on se lance dans la conception d’un site internet, on se heurte très rapidement aux problèmes d’authentification.

Un site a, le plus souvent, une ou plusieurs zones réservées, et la gestion de ces zones ne peut se faire sans avoir quelques notions sur les différentes manières de gérer les autorisations. Il existe 3 façons de coder celles-ci.

Un exemple simple : Le Livre d’Or.

Ce que l’on appelle un livre d’Or n’est ni plus ni moins qu’un forum ultra simplifié. Il y a les lecteurs/rédacteurs, et l’administrateur.
Les lecteurs/rédacteurs peuvent lire et écrire, alors que l’administrateur peut également effacer des messages. On se retrouve avec 2 cas à gérer :

  • Le cas de « tout le monde »
  • Le cas de l’administrateur

En réfléchissant un peu, on s’aperçoit que l’on a un seul cas : L’administrateur. En effet, dans le déroulement du programme, tout le monde peut lire et écrire. Il n’y aura donc pas de condition pour cela. Par contre, il faudra une condition pour administrer le Livre d’Or. Donc, on pourra écrire :

Si la personne est ‘administrateur’, alors
elle peut effacer les messages

Dans tous les cas, elle peut lire et écrire un message.

En programmation, ce type de cas se résoud par un simple ‘booléen’.

$autorisation_membre = 'administrateur' ? oui : non;

Un exemple de code :

$autorisation_membre = TRUE;

if ($autorisation_membre) {

echo "A le droit d'effacer";
}
else{
echo "N'a pas le droit d'effacer";
}
echo"
A le droit d'écrire";
echo"
A le droit de lire";

Changez la variable $autorisation_membre en FALSE, pour voir ce que donne le code.

Un exemple plus complexe : Le Forum simplifié.

Ce que j’appelle ici un forum simplifié n’est pas forcément un forum d’apparence simple, mais un forum qui gère les autorisations des membres de façon simplifiée.

Ce forum possède 3 (ou plus) zones membres différentes.

La première zone est l’accès à tous les visiteurs. Elle n’a pas besoin d’authentification, donc pas besoin de boucles conditionnelles ( if(…) ).
La zone suivante est réservée aux modérateurs. ils ont les mêmes droits qu’un visiteur ‘normal’. Mais en plus, ils peuvent modifier un message, et mettre en ‘modération’ un message litigieux. Autrement dit, le mettre de coté, en vue de l’éditer ou de l’effacer.
La zone suivante est réservée aux administrateurs. Ils ont les mêmes droits qu’un visiteur, les mêmes droits qu’un modérateur, mais ils peuvent, en plus effacer un message et décider du sort des messages en modération.
etc…

On s’aperçoit, très vite, que l’on peut schématiser les droits de chacun suivant une arborescence.

  • 1 : membres : lire écrire
  • 2 : modérateurs : lire écrire modifier modérer
  • 3 : administrateurs : lire écrire modifier modérer effacer
  • Les utilisateurs 3 ont les droits de 3, de 2 et de 1,
  • Les utilisateurs 2 ont les droits de 2 et de 1,
  • Les utilisateurs 1 ont les droits de 1.

On peut ainsi décliner tout un tas de ‘services’, tout un tas de zones. Chacune sera gérée, au niveau des autorisations, comme l’exemple ci-dessus, à la manière d’une arborscence.

En programmation, il suffit de définir les droits, le niveau de chacun. Ensuite, dans le programme, il suffira de vérifier que le niveau d’un utilisateur est égal ou supérieur au niveau demandé pour la zone concernée.

Un exemple :

$autorisation_membre = 2; // c'est un modérateur.

if ($autorisation_membre >=1)
echo" bouton ecrire ";

if ($autorisation_membre >=2)
echo" bouton mettre ce post en modération ";

if ($autorisation_membre >=3)
echo" bouton supprimer ce message ";

On définit donc les boutons qui permettent de faire telle ou telle action, en fonction des niveaux d’autorisation de chacun.
Les entrées de zone se feront avec la même identification.

Le troisième exemple : Le bit bashing.

Si l’exemple du forum simplifié suffit dans bien des cas, il peut s’avérer insuffisant pour gérer certains cas particuliers.

Un exemple trivial (sans vouloir porter aucun jugement) :

Le directeur a les clés du bureau du directeur, les clés du bureau du chef, les clés du bureau des employés.
Le chef a les clés du bureau du chef et de l’employé,
L’employé a les clés du bureau des employés.

Jusque là, on pourrait se servir de l’exemple en arborescence cité plus haut. Seulement, certains employés ont aussi les clés du bureau du directeur, et du bureau du chef. Il s’agit, par exemple, de la femme de ménage, du technicien, etc.

Donc, la réalité n’est pas si simple.

Faut-il, dans le programme, prévoir tous les cas ? Non, évidement. Techniquement, l’astuce consiste à utiliser les bits.

Pour expliquer par l’exemple, on va imaginer des cours d’informatique. Il y a différents cours, notamment sur la programmation. Les élèves ont à choisir entre les cours d’ASP, PHP, C++, Java et Delphi. Une méthode consisterait à créer un tableau, pour chaque élève, où l’on répertorierait tous les cours, et pour chacun, le statut de l’élève : suit ce cours, ou ne le suit pas. Cela prend de la place, puisque cela oblige à tenir à jour un grand tableau, et les modifications deviennent rapidement empiriques, si le nombre de cours augmente.

Pour notre exemple, nous allons assigner un bit à chaque cours.

nom binaire base 10
ASP 0 0 0 0 0 0 1 1
PHP 0 0 0 0 0 1 0 2
C++ 0 0 0 0 1 0 0 4
Java 0 0 0 1 0 0 0 8
Delphi 0 0 1 0 0 0 0 16
Perl 0 1 0 0 0 0 0 32

On assigne donc un niveau à chacun de ces cours, en notant, dans la colonne du milieu, la valeur en binaire de ce niveau.

Le cours PHP a le niveau 2, ce qui correspond à ‘0000010’ en notation binaire, alors que le Java a le niveau 8, ce qui correspond, en binaire, à 0001000. En additionnant ces deux valeurs binaires, on obtient 0001010, soit 0000010+0001000. En base 10, ça correspondrait à 8+2=10.

Le code ?

$cours1="8";
$cours2="2";

echo"

décimale :";
echo"
cours 1 : ".$cours1;
echo"
cours 2 : ".$cours2;

echo"
cours 1 + cours 2 : ".($cours1+$cours2);
echo"

binaire :";
echo"
cours 1 : ".decbin($cours1);
echo"
cours 2 : ".decbin($cours2);
echo"
cours 1 + cours 2 =".decbin($cours1+$cours2);

Sorie écran :

décimale :
cours 1 : 8
cours 2 : 2
cours 1 + cours 2 : 10

binaire :
cours 1 : 1000
cours 2 : 10
cours 1 + cours 2 : 1010

Outre les fonctions decbin() qui permet de passer d’une valeur décimale en binaire, et bindec() qui permet de passer d’une valeur binaire en valeur décimale, on s’aperçoit que l’on retombe bien sur nos pieds. 8 + 2 = 10 et 0000010 + 0001000 = 0001010.

En pratique ?

Additionner les valeurs binaires peut ne présenter aucun intérêt. On a vu que 8+2=10, en décimal, ou en binaire. L’intérêt réel de la méthode du bit bashing réside dans les boucles conditionnelles.

Les tests conditionnels avec des bits sont d’une simplicité enfantine.

Un exemple expliqué :

<?php
// on définit les cours :
define("asp",1 define("php",1 define("c++",1 define("java",1 define("delphi",1 define("perl",1
// on définit les choix du membre
$choix_membre = asp | php | java;

// que l'on affiche à l'écran pour 'une meilleure visibilité' ;)
echo"Choix : asp | php | java";

// et on teste :
echo "

php ? : ".((php & $choix_membre)?"ok":" non ok");
echo "
java ? : ".((java & $choix_membre)?"ok":" non ok");
echo "
delphi ? : ".((delphi & $choix_membre)?"ok":" non ok");
echo "
C++ ? : ".(("C++" & $choix_membre)?"ok":" non ok");

// Jusque là, c'est pas trop compliqué...
// on passe donc à la suite :
echo"

";

// ca marche avec un cours, essayons avec plusieurs :
// les tests où ca marche :
echo "
php AND java ? : ".(( (php AND java) & $choix_membre)?"ok":"non ok");

// les tests où ca marche pas :
echo"

";
echo "
php AND delphi ? : ".((php AND delphi & $choix_membre)?"ok":"non ok");
echo "
delphi AND C++ ? : ".((delphi AND "C++" & $choix_membre)?"ok":"non ok");
echo "
php OR java ? : ".((php OR java & $choix_membre)?"ok":"non ok");
echo "
delphi OR C++ ? : ".((delphi OR "C++" & $choix_membre)?"ok":"non ok");

?>

La sortie écran de tout ceci donnera :

Choix : asp | php | java

php ? : ok
java ? : ok
delphi ? : non ok
C++ ? : non ok

php OR java ? : ok
php AND java ? : ok

php AND delphi ? : non ok
delphi AND C++ ? : non ok
delphi OR C++ ? : ok

On s’aperçoit que le dernier test ne marche pas ..L’avant dernier test non plus, mais ca passe inaperçu.. Explications ?

Ceci est dû au fait que l’on ne peut faire de test « OR » sur les bits. En effet, les opérations sont effectuées de droite à gauche, et quand on décompose le code qui renvoie la dernière ligne, ça donne :

delphi OR "C++" & $choix_membre

=> TRUE OR FALSE & TRUE
=> TRUE OR FALSE
=> TRUE

Résultat, le test retourne ‘true’, alors que l’on s’attendrait à un ‘false’.

S’il faut tester les 2 cours, il faudra donc décomposer le test :

(delphi & $choix_membre) OR ("C++" & $choix_membre)

Le code ci-dessus peut prendre en compte les tableaux, ou les bases de données :

exemple :

$a=array("asp","php","c++","java","delphi","perl");
foreach ($a as $key=>$value) define($value,1

Très facile à mettre en oeuvre, il permet de gérer les authentifications sans se soucier des niveaux tel que cela apparaissait dans l’exemple du ‘forum simplifié’.