2012-02-22 9 views
21

Quali sono le buone strategie per l'autorizzazione basata sui ruoli in express.js? Soprattutto con express-resource?Approccio di autorizzazione basato su gruppi/regole in node.js e express.js

Con Express-resource non ci sono i gestori, quindi penso che ci sono tre opzioni:

  1. utilizzare un middleware
  2. Passare la funzione di autorizzazione alla risorsa e controllare ogni richiesta di risorse separatamente
  3. controllo di autorizzazione con ogni richiesta subito dopo l'autenticazione

Esistono altre soluzioni?

L'autorizzazione di gruppo/ruolo è un approccio piuttosto antico. Esistono metodi più nuovi per il controllo degli accessi? In caso contrario, come può essere applicata l'autorizzazione basata sui ruoli a node.js? Dove conservare le relazioni delle regole di gruppo (con NoSQL/CouchDB/Redis)?

A titolo di esempio, la struttura:

/ 
    /forums 
    /forums/threads 

Ogni risorsa con indice, nuovo, creare, visualizzare, modificare l'aggiornamento e distruggere. Alcune persone possono modificare/eliminare ecc. Discussioni e forum, alcune persone non dovrebbero.

risposta

11

Connect-roles è abbastanza buono, semplice e la documentazione è anche molto chiaro.

var user = roles; 

app.get('/profile/:id', user.can('edit profile'), function (req, res) { 
    req.render('profile-edit', { id: req.params.id }); 
}) 
app.get('/admin', user.is('admin'), function (req, res) { 
    res.render('admin'); 
} 
3

In express è possibile aggiungere un gestore che si aggancia a ogni operatore (http://expressjs.com/guide.html#passing-route control) in cui è possibile eseguire la convalida della precondizione. Qui puoi recuperare il ruolo per l'utente e limitare l'accesso in base al verbo HTTP (PUT, DELETE, ecc.) O all'URL (param('op') è 'modifica' o così).

app.all('/user/:id/:op?', function(req, res, next){ 
    req.user = users[req.params.id]; 
    if (req.user) { 
    next(); 
    } else { 
    next(new Error('cannot find user ' + req.params.id)); 
    } 
}); 
+0

Sfortunatamente, come già detto, non funziona con le risorse espresse. – Patrick

32

direi che è difficile per risolvere questo in modo pulito usando espresso in termini di risorse, in quanto non permette di middleware specifiche percorso (almeno non in modo pulito).

Vorrei optare per un layout simile come un modulo di risorse espresso, ma instradarlo con semplice vecchio espresso. Qualcosa di simile a questo:

// Resource 
var forum = { 
    index: // ... 
    show: // ... 
    create: // ... 
    update: // ... 
    destroy: // ... 
}; 

// Middleware 
var requireRole = function(role) { 
    return function(req, res, next) { 
    if('user' in req.session && req.session.user.role === role) 
     next(); 
    else 
     res.send(403); 
    } 
}; 

// Routing 
app.get('/forums', forum.index); 
app.get('/forums/:id', forum.show); 
app.post('/forums', requireRole('moderator'), forum.create); // Only moderators can create forums 
app.delete('/forums/:id', requireRole('admin'), forum.destroy); // Only admins can delete forums 

UPDATE: Ci sono state discussioni in corso in materia di middleware specifiche percorso in espresso in termini di risorse, ad esempio, here. L'opinione prevalente sembra essere quello di avere una matrice per azione, per es .:

var forums = { 
    index: [ requireRole('foo'), function(req, res, next) { ... } ] 
}; 

Si potrebbe prendere uno sguardo attraverso le richieste di trazione e vedere se c'è qualcosa che si può usare. Capisco perfettamente, ovviamente, se non ti senti a tuo agio con quello. Sono abbastanza sicuro che vedremo qualcosa di simile in express-resource in futuro.

L'unica altra soluzione che posso pensare è lungo le linee di risposta di Jan Jongboom, che potrebbe essere quella di montare le risorse con espressa in termini di risorse, ma hanno middleware attaccato "al di fuori" di quella, qualcosa di simile:

app.delete('*', requireRole('admin')); // Only admins are allowed to delete anything 
app.put('/forums/*', requireRole('moderator')); // Only moderators are allowed to update forums 

Ma mi dispiace che questo perde gli URL dappertutto.

+0

Il problema è che ci sono una discreta quantità di risorse ed è abbastanza pulito con express-resource. Sto pensando a un piccolo modulo che posso usare con app.use(), ma non so come scriverlo. – Patrick

+0

Patrick, sono assolutamente d'accordo. Vedi il mio aggiornamento sopra per ulteriori discussioni. Ci sono più richieste di pull rispetto a quella a cui mi riferisco riguardo a questo. Non ne sono sicuro, ma ho la sensazione che TJ lavorerà di più su express-resource, express-namespace & co dopo che 3.0 è fuori dalla porta, sembra che ci siano parecchi cambiamenti. –

2

Ho scritto un modulo come middleware di instradamento non esplicito. Funziona bene con percorsi espressi.

Gandalf on GitHub

+0

Grazie a @Patrick per il middleware. C'è un buon esempio su come usarlo con expressjs. Mi dispiace se suona come una domanda di noobs Sono abbastanza nuovo per nodejs ed express. L'esempio sarà fantastico grazie – praneybehl

+0

@praneybehl Raccomando di andare con i ruoli di connessione o l'approccio di Linus. Il middleware di Gandalf è obsoleto. – Patrick

26

Ho svolto ricerche sulla stessa domanda e ho riscontrato alcuni buoni moduli. Mi sono concentrato sul pacchetto node-acl che può essere trovato qui. https://github.com/optimalbits/node_acl.

Questo pacchetto sembra aver implementato il pattern ACL in un modo molto comprensibile e ha fornito modi per integrarlo facilmente nell'applicazione nodo/Express.

In primo luogo, è necessario definire le risorse, i ruoli e le autorizzazioni.

Per esempio, le risorse possono essere:

/ 
    /forums 
    /forums/threads 

I ruoli possono essere

public 
admin 
user 
    john 
    jane 

In questo esempio, i ruoli John e Jane può mappare agli account utente reali, ma perché erediteranno tutte le autorizzazioni del ruolo utente.

Le autorizzazioni per le risorse

  • creano
  • mostrano
  • aggiornamento
  • distruggere

O le operazioni CRUD standard.

Ora che quelli sono stati definiti, possiamo dare un'occhiata a come sembrerebbe impostare l'acl usando node-acl. Queste note sono derivati ​​dalla documentazione

importazione pacchetto

var acl = require('acl'); 

Impostare il backend. La mia applicazione sta usando MongoDB, ma il pacchetto di nodo-ACL non supporta altri meccanismi di stoccaggio

acl = new acl(new acl.mongodbBackend(dbInstance, prefix)); 

mia applicazione sta usando in modo mangusta dbInstance sarebbe sostituito con mongoose.connection.db

Ora lascia aggiungere i nostri ruoli da l'ACL. In node-acl, i ruoli vengono creati concedendo loro le autorizzazioni. E 'come prendere due piccioni con una fava (no uccelli sono in realtà danneggiati)

acl.allow('admin', ['/', '/forum', '/forum/threads'], '*'); 
acl.allow('public', ['/', '/forum', '/forum/threads'], 'show'); 
acl.allow('user', ['/', '/forum', '/forum/threads'], ['create', 'show']); 

Consente assumere una nuova risorsa è stato creato da John, aggiungeremo un nuovo record che permette a John di aggiornare e cancellare anche quella risorsa.

acl.allow('john', ['/forum/threads/abc123'], ['update', 'delete']); 

Anche la mia applicazione utilizza express, quindi userò l'approccio del routing middleware per controllare i percorsi.Nella mia configurazione di routing, vorrei aggiungere la linea

Nella maggior parte delle configurazioni Express, questo appare come per i pos

app.post('/', acl.middleware(), function(req, res, next) {...}); 
app.post('/forums', acl.middleware(), function(req, res, next) {...}); 
app.post('/forums/:forumId', acl.middleware(), function(req, res, next) {...}); 
app.post('/forums/threads', acl.middleware(), function(req, res, next) {...}); 
app.post('/forums/threads/:threadId', acl.middleware(), function(req, res, next) {...}); 

Quando sono passate alcun parametro, questo controlla se il ruolo definito nella req.userId è permesso di eseguire il metodo http sulla risorsa identificata ma sulla rotta.

In questo esempio il metodo http è post, ma farà la stessa cosa per ogni http identificato nella configurazione.

Ciò solleva la domanda, in merito alle autorizzazioni definite in precedenza. Per rispondere a queste domande, avremmo dovuto cambiare i permessi da

  • creare
  • mostrano
  • aggiornamento
  • distruggere

al tradizionale

  • posta
  • ottenere
  • messo
  • eliminare

Sebbene questo esempio mostra tutto hardcoded, la pratica migliore è quella di avere un'interfaccia di gestione per le autorizzazioni in modo che possano essere creati, leggere, aggiornati ed eliminati in modo dinamico, senza dover per modificare il codice.

Mi piace l'approccio plug-in di nodo-acl in quanto consente assegnazioni di ruoli di autorizzazione a grana molto fine utilizzando un api molto semplice e flessibile. C'è molto di più nella loro documentazione, il mio esempio mostra che io sono con il pacchetto.

Speriamo che questo aiuti.

+0

cos'è pubblico? sto avendo difficoltà a rendere la risorsa pubblica non protetta – danielad

Problemi correlati