3 votes

Contrôle d'accès et demandes XHR

J'ai du mal à mettre en œuvre un contrôle d'accès pour un cadre personnalisé.

La granularité RBAC n'est pas nécessaire, j'ai donc décidé d'utiliser une sorte d'ACL où les ressources seront actions du contrôleur.

Voici la structure de la base de données :

utilisateurs :

  • John
  • Mary
  • Greg

groupes_utilisateurs :

  • Administrateurs
  • Comptables
  • Managers

utilisateurs_à_groupes_d'utilisateurs :

  • John => Administrateurs
  • Mary => Comptables
  • Greg => Managers

ressources (actions du contrôleur) :

  • utilisateurs/edit
  • factures/addition
  • clients/suppression

ressources_vers_les_groupes_d'utilisateurs :

  • users/edit => Administrateurs
  • factures/ajouts => Comptables
  • customers/delete => Managers

Et voici le [pseudo]code.

$user = new User; // This will be currently logged in user ...

$acl = new Acl($user);

$dispatcher = new Dispatcher($acl);

$dispatcher->dispatch('users', 'new');

class Dispatcher
{
    public function dispatch($controller, $action)
    {
        $permission = $controller . '/' . $action;

        if(!$this->acl->isAllowed($permission))
        {
            throw new AccessDeniedException("Access denied");
        }

        // User is authorized to execute this action, dispatch ...
    }
}

J'ai aimé cette approche... jusqu'à ce que je réalise qu'il y a aussi beaucoup de requêtes XHR.

Par exemple, la liste des factures utilise une requête XHR pour obtenir le montant total, la liste des commandes utilise des requêtes XHR. pour charger les positions des commandes et d'autres données, etc.

Il doit donc y avoir un regroupement des ressources, par exemple, une nouvelle table resource_groups :

  • Liste des factures (factures/liste, factures/xhr_get_total_amount)
  • Liste des commandes (commandes/list, commandes/xhr_get_positons_for_order, commandes/xhr_get_some_other_data)
  • Ajouter un nouvel utilisateur (users/new) # Action unique, le formulaire d'entrée d'un nouvel utilisateur n'utilise pas de requêtes XHR

... et au lieu d'affecter des ressources à des groupes d'utilisateurs, affectez des groupes de ressources à des groupes d'utilisateurs.

Ça semble si compliqué. Est-ce la bonne façon de procéder ? Que peut-on améliorer ? Est-ce qu'un cadre quelconque aborde ce problème ?

2voto

Sobit Akhmedov Points 392

Pourquoi ne pas simplement ajouter une nouvelle colonne à resources tableau, appelé descendants qui stockera un tableau de ressources xhr dépendantes ? Cela pourrait donc ressembler à ça :

resource: "invoices/list"
descendants: ["invoices/xhr_get_total_amount"]

resource: "orders/list"
descendants: ["orders/xhr_get_positons_for_order","orders/xhr_get_some_other_data"]

resource: "users/new"
descendants: []

Aussi, si ce n'est pas encore implémenté : vous pouvez obtenir et traiter toute la liste des ressources autorisées et leurs descendants dans un tableau unique au début de la requête et les stocker jusqu'à la réponse. Ainsi, vous ne demanderez pas à la base de données chaque fois que vous aurez besoin de vérifier l'accès à quelque chose.

2voto

Mehran Points 2068

J'ai été confronté au même problème l'année dernière et voici comment je l'ai résolu.

Tout d'abord, j'ai utilisé ACL de Zend Framework comme moteur de base pour me dire si un utilisateur a accès à une ressource. Comme ZF prend déjà en charge les groupes d'utilisateurs et les rôles (y compris la hiérarchie des rôles), vous n'avez plus à vous soucier de cela.

Si l'on met de côté les groupes d'utilisateurs et les rôles, le groupe suivant serait le groupe de ressources que ZF ne prend pas en charge en interne (malheureusement). Et je crois que c'est la partie sur laquelle porte votre question. Pourtant, vous pouvez utiliser ZF et l'étendre pour répondre à vos besoins. Tout ce que vous avez à faire est d'imaginer un mécanisme de regroupement des ressources (plat ou hiérarchique). Ensuite, vous pouvez utiliser ZF comme il est indiqué dans son manuel.

Voici un exemple de la façon de procéder :

  1. Construire le moteur ACL et d'autres objets de base :

    $acl = new Zend_Acl();
    
    $acl->addRole(new Zend_Acl_Role('guest'))
        ->addRole(new Zend_Acl_Role('member'))
        ->addRole(new Zend_Acl_Role('admin'));
    
    $parents = array('guest', 'member', 'admin');
    $acl->addRole(new Zend_Acl_Role('someUser'), $parents);
  2. Définissez votre groupement de ressources :

    $resources = array(
        'group 1' => array(
            'resource 1'
            , 'resource 2'
            , 'resource 3'
        )
        , 'group 2' => array(
            'resource 1'
            , 'resource 4'
            , 'resource 5'
        )
    );
  3. Présentez vos ressources au moteur de l'ACL :

    function addResource(Zend_Acl $acl, $resources, $groupName)
    {
        foreach ($resources[$groupName] as $resource) {
            $acl->add(new Zend_Acl_Resource($resource));
        }
    }
    
    addResource($acl, $resources, 'group 2');
  4. Utilisez le moteur de l'ACL pour interroger les permissions :

    echo $acl->isAllowed('someUser', 'resource 1') ? 'allowed' : 'denied';

Comme vous pouvez le voir, je n'ai rien fait de spécial ici. Le seul nouveau concept introduit ici était que les ressources ajoutées au moteur ACL étaient différentes de celles utilisées pour l'interroger. Mais cela a été fait une couche avant que nous appelions la bibliothèque de ZF, donc les appels pour interroger l'ACL de ZF fonctionnent toujours.

J'espère avoir pu écrire mon point de vue clairement. Et n'oubliez pas que j'essaie juste de vous donner un concept, vous devez trouver vous-même la mise en œuvre réelle.

1voto

DudeOnRock Points 637

Je sais que je ne réponds pas directement à votre question, mais je peux peut-être vous mettre sur une voie légèrement différente qui sera beaucoup plus flexible lorsque votre site web aura grandi en taille et en complexité. Après avoir lu este post J'ai changé mon système d'authentification pour le baser sur l'activité (autoriser l'activité "doSomething"), et non plus sur le rôle ("administrateur" peut faire ce qui suit....).

Juste une idée.

1voto

tntu Points 3041

Il est préférable de ne pas utiliser * mais le domaine qui demande le fichier. Le * échouera dans une certaine version d'IE (je ne me souviens plus laquelle).

if ($ref_url)
  header("Access-Control-Allow-Origin:"+$ref_url);
else
  header("Access-Control-Allow-Origin:*");

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X