web-dev-qa-db-fra.com

MongoDB + Node JS + Contrôle d'accès basé sur les rôles (RBAC)

J'apprends actuellement MEAN stack, développant une application TODO simple et souhaitant implémenter le contrôle d'accès basé sur les rôles (RBAC) pour cela. Comment configurer les rôles et les autorisations sur MongoDB.

Je veux 3 rôles (les rôles peuvent sembler drôles mais c'est purement à apprendre):

  • DIEU
  • SUPER HERO
  • MAN

DIEU - similaire au super administrateur, peut faire n'importe quoi dans l'application. Autorisations C, R, U, D pour TODO et pour d'autres utilisateurs également. Peut créer un TODO et l'affecter à n'importe quel SUPER HERO ou MAN directement. Mettez à jour ou supprimez un TODO ou un utilisateur à tout moment.

SUPER HERO - similaire à l'administrateur, a le super pouvoir de faire quoi que ce soit sur ses données personnelles - C, R, U, D pour TODO. Impossible de créer des utilisateurs. Peut seulement lire et ajouter des commentaires pour les TODO créés par DIEU et assignés à lui/elle.

MAN - Peut uniquement lire et ajouter des commentaires aux TODO qui lui sont assignés.

Résumer :

GOD - C,R,U,D [Global Level] SUPER HERO - C,R,U,D [Private] + R,U [Assigned to him] MAN - R,U [Assigned to him]

Je comprends que j'ai besoin d'avoir des collections USERS & ROLES. Où ROLES inturn devrait avoir des AUTORISATIONS, etc. Comment les câbler tous?

15
BeingSuman

J'aime les noms donnés aux rôles - DIEU, SUPER HÉROS ET HOMME, facile à comprendre.

Comme vous utilisez la pile MEAN et que la plupart des validations de routes se font sur node, je préférerais garder la table des rôles simple.

Rôles:

{
_id : 1,
name : GOD,
golbalPerms : true
},
{
_id : 2,
name : SUPER HERO,
privatePerms : true
},
{
_id : 3,
name : MAN
}

tilisateurs:

{
_id : 111,
name : Jesus,
roleId : 1
},
{
_id : 222,
name : BatMan,
roleId : 2
},
{
_id : 333,
name : Jack,
roleId : 3
}

Lorsque l'utilisateur se connecte et renvoie l'objet user au client, assurez-vous de remplacer roleId par l'objet role correspondant de la base de données.

Venir coder sur Node JS:

En comprenant parfaitement votre cas d'utilisation, nous pouvons les diviser en méthodes suivantes -

  • Créer un utilisateur

  • CreateTodo

  • DeleteTodo

  • ReadTodo

  • UpdateTodo
  • CommentTodo

  • AssignTodo

Permet d'aller étape par étape, CreateUser.

Extrait de code de routes:

app.all('/users', users.requiresLogin);

// Users Routes
app.route('/users')
    .post(users.hasPerms('globalPerms'), users.create);

Dans votre contrôleur, vous pouvez valider en fonction de l'entrée globalPerms, si elle est validée, autorisez la création d'un utilisateur en appelant next() else return avec le message d'erreur correspondant.

Maintenant CreateTodo && DeleteTodo:

Les deux fonctionnent à peu près sur la même logique avec une petite astuce.

Extrait de code de routes:

app.all('/todos', users.requiresLogin);

// Users Routes
app.route('/todos')
    .post(users.hasPerms('globalPerms','privatePerms'), todos.create);
    .delete(users.hasPerms('globalPerms','privatePerms'), todos.delete);

Pour créer un Todo, globalPerms sont avec DIEU & privatePerms sont avec SUPER HERO, les deux peuvent être autorisés.

L'astuce ici sera dans la méthode todos.delete, Assurez-vous simplement que user.id === todos.createById Sinon SUPER HERO peut continuer à supprimer les Todos créés par DIEU.

ReadTodo:

Lorsqu'un TODO est créé, il devrait avoir un createById stocké de même lorsqu'un TODO est assigné à quelqu'un, alors assignedTo et assignedBy doivent également être enregistrés.

Cela rend beaucoup d'autres opérations faciles à gérer.

user.role.globalPerms - donnez à DIEU toutes les données de TODO.

user.role.privatePerms - donnez les TODO créés par lui/elle ou assignés à lui.

user.role.globalPerms === undefined && user.role.privatePerms === undefined - c'est MAN et donnez les TODO qui ne lui sont attribués que.

pdateTodo & CommentTodo:

Ceci est une réplique exacte de ce que ReadTODO fait si bricolage

Dernier, AssignTodo:

Simple, loggedInUser.id === todos.createdById Alors il peut l'attribuer à n'importe qui.

Deux choses à garder à l'esprit ici:

  1. Comme l'attribution d'une partie se produit principalement sur votre interface utilisateur (angulaire), j'ai donné cette approche de vérification loggedInUser.id === todos.createdById. L'utilisateur connecté de quelque manière que ce soit verra tous les TODO par opération de lecture et pourra les affecter à tous ceux qu'il/elle aime.

  2. Assurez-vous qu'un SUPER HERO ne peut assigner un TODO qu'à lui-même ou à un autre SUPER HERO ou à un MAN mais pas à DIEU. Comment vous montrez Attribuer aux options sur l'interface utilisateur est hors de portée de cette question.

J'espère que c'était clair.

REMARQUE: il n'était pas nécessaire de donner des autorisations à MAN dans la collection de rôles et nous avons géré toutes les opérations possibles sans cela.

22
swetha akula

Il s'agit d'une question très large qui peut être résolue de plusieurs manières.

Vous avez ajouté que vous utilisez la pile MEAN donc je limiterai ma question à cela.

Une chose que vous n'avez pas incluse dans toute la question est le type d'architecture d'authentification que vous utilisez. Supposons que vous utilisez l'authentification par jeton, généralement les gens l'utilisent de nos jours.

Nous avons 3 types d'utilisateurs. Vous disposez également de différentes options pour différencier les types de jetons.

  1. Différents ensembles Collection (mongoDB) ou Redis où ils seront stockés
  2. Le jeton chiffré aura également le type d'utilisateur, etc. (cela vous sera utile si vous n'avez pas besoin de stocker des jetons sur le backend, vous pouvez simplement le déchiffrer et le vérifier)

    • Cela dépendra entièrement du cas d'utilisation.

Maintenant, avant d'autoriser l'entrée d'un utilisateur sur un itinéraire spécifique à l'utilisateur, assurez-vous que vous vérifiez d'abord le jeton.

Exemple

app.post('/godlevelroute', godtokencheck, callrouteandfunction);
app.post('/superherolevelroute', superheroroute, callrouteandfunction);

Vous devez envoyer un jeton dans l'en-tête de angular et ensuite vous pouvez retirer les données de l'en-tête et ensuite vous pouvez vérifier si cet utilisateur spécifique a la permission de passer par cette route ou non.

Disons qu'un utilisateur de niveau divin est connecté, il aura le godleveltoken avec lui et nous le vérifierons d'abord avant de lui permettre d'accéder à cette route, sinon vous pouvez simplement afficher un message d'erreur.

Cela peut être votre exemple de fonction de vérification des jetons côté serveur

function checkToken(req, res, next) {
var token = req.headers['accesstoken']; //access token from header
//now depending upon which system you are following you can run a check
};

Suggestion de module de nœud: https://www.npmjs.com/package/jsonwebtoken

Maintenant à venir pour la partie frontend. Vous utilisez angular en fonction de ce que vous avez écrit, vous pouvez intercepter le jeton avant d'afficher une page.

Vous pouvez parcourir ce blog pour obtenir une représentation imagée de ce que j'ai essayé d'expliquer. Cliquez ici

2

Approche possible-> avoir un rôle intégré dans la collection/le schéma utilisateur: le document utilisateur doit avoir les éléments suivants:

{
    _id : "[email protected]",
    name: "lorem ipsum",
    role: "MAN"
}

Pour autant que votre message le décrit, seul Dieu peut créer et attribuer des TODO. La collection de rôles peut contenir les éléments suivants:

{
    _id : "MAN",
    globalPerm: [],
    privatePerm: [],
    assignedPerm: ["r","u"],
},
{
    _id : "SUPER_HERO",
    globalPerm: [],
    privatePerm: ["c","r","u","d"],
    assignedPerm: ["c","r","u","d"],
},
{
    _id : "GOD",
    globalPerm: ["c","r","u","d"],
    privatePerm: ["c","r","u","d"],
    assignedPerm: ["c","r","u","d"],
}

Node JS Middlewares Après avoir obtenu les valeurs d'autorisation correctes pour un utilisateur, vous pouvez utiliser des middlewares. Exemple d'itinéraire de demande HTTP express:

app.post('/updateTodo', permissions.check('privatePerm', 'c'), function (req, res) {
 // do stuff

};

permissions.check est appelé avant d'exécuter réellement le corps de la fonction pour mettre à jour TODO.

Par conséquent, si un utilisateur essaie de mettre à jour une tâche, il vérifiera d'abord les autorisations correspondantes.

0
inaitgaJ