Podejście autoryzacyjne oparte na grupach / regułach w węźle.js i express.js

Jakie są dobre strategie autoryzacji opartej na rolach w programie express.js? Zwłaszcza z express-resource?

Z Express-resource nie ma obsługi, więc myślę, że są trzy opcje:

  1. Użyj middleware
  2. przekazać funkcję autoryzacji do zasobu i sprawdzić każde żądanie zasobu oddzielnie
  3. sprawdzanie autoryzacji przy każdym żądaniu zaraz po uwierzytelnieniu

Czy są jakieś inne rozwiązania?

Group/Role-based authorization to dość antyczne podejście. Czy istnieją nowsze metody kontroli dostępu? Jeśli nie, w jaki sposób można zastosować autoryzację opartą na rolach do węzła.js? Gdzie przechowywać relacje reguły grupy (z NoSQL / CouchDB / Redis)?

Jako przykład struktura:

/
  /forums
    /forums/threads

Każdy zasób z indeksem, nowy, tworzyć, pokazywać, edytować aktualizować i niszczyć. Niektóre osoby mogą edytować / usuwać itp. wątki i fora, niektórzy nie powinni.

Author: Patrick, 2012-02-22

5 answers

Connect-roles jest całkiem dobry, prosty i dokumentacja jest również bardzo przejrzysta.

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');
}
 12
Author: Zainan Victor Zhou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-11 09:50:56

Powiedziałbym, że trudno jest rozwiązać to w czysty sposób za pomocą express-resource, ponieważ nie pozwala to na użycie oprogramowania pośredniczącego specyficznego dla trasy (przynajmniej nie w czysty sposób).

Wybrałbym podobny układ jak moduł express-resource, ale przekierowywałbym go za pomocą zwykłego starego expressa. Coś takiego:

// 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

Aktualizacja: trwają dyskusje na temat specyficznego dla trasy oprogramowania pośredniego w express-resource, np. tutaj . Panujący pogląd wydaje się mieć tablica na akcję, np.:

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

Możesz przejrzeć żądania pull i zobaczyć, czy jest coś, czego możesz użyć. Rozumiem to, jeśli nie czujesz się z tym komfortowo. Jestem pewien, że coś takiego zobaczymy w express-resource w przyszłości.

Jedyne inne rozwiązanie, jakie mogę wymyślić, to odpowiedź Jana Jongbooma, która polegałaby na zamontowaniu zasobów za pomocą express-resource, ale mieć dołączone oprogramowanie pośredniczące "Na Zewnątrz" to coś w stylu:

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

Ale żałuję, że to wycieka adresy URL wszędzie.

 32
Author: Linus Gustav Larsson Thiel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-28 14:12:56

Badałem to samo pytanie i natknąłem się na kilka dobrych modułów. Skupiłem się na pakiecie node-acl, który można znaleźć tutaj. https://github.com/optimalbits/node_acl .

Wydaje się, że ten pakiet zaimplementował wzorzec ACL w bardzo zrozumiały sposób i zapewnił sposoby łatwej integracji go z aplikacją node/express.

Najpierw musisz zdefiniować swoje zasoby, role i uprawnienia.

Na przykład, zasoby mogą być:

/
  /forums
    /forums/threads

Role mogą być

public
admin
user
   john
   jane

W tym przykładzie role john i jane mogą mapować do rzeczywistych kont użytkowników, ale odziedziczą wszystkie uprawnienia do roli użytkownika.

Uprawnienia do zasobów

  • Utwórz
  • Pokaż
  • update
  • destroy
Albo standardowe operacje CRUD.

Teraz, gdy zostały one zdefiniowane, możemy przyjrzeć się, jak wyglądałoby skonfigurowanie acl używając node-acl. Uwagi te pochodzą z dokumentacji

Importuj pakiet

var acl = require('acl');

Skonfiguruj swój backend. Moja aplikacja używa mongodb, ale pakiet node-acl obsługuje inne mechanizmy przechowywania]}

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

Moja aplikacja używa mangusty, więc dbInstance zostanie zastąpiony mangustą.połączenie.db

Teraz dodajmy nasze role do ACL. W node-acl role są tworzone przez nadanie im uprawnień. To jak zabicie dwóch ptaków jednym kamieniem (żadne ptaki nie są w rzeczywistości hurt)

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

Załóżmy, że nowy zasób został stworzony przez Johna, dodamy nowy rekord, który pozwala Johnowi również aktualizować i usuwać ten zasób.

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

Moja aplikacja również używa express, więc użyję podejścia routing middleware do sprawdzania tras. W mojej konfiguracji routingu dodałbym linię

W większości konfiguracji ekspresowych wygląda to tak dla 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) {...});

Gdy nie zostaną przekazane żadne parametry, sprawdzi to, czy rola zdefiniowana w req.userId może wykonywać metodę http na zidentyfikowanym zasobie, ale na trasie.

W tym przykładzie metoda http to post, ale zrobi to samo dla każdego identyfikowalnego http w Twojej konfiguracji.

Nasuwa się pytanie o uprawnienia zdefiniowane wcześniej. Aby odpowiedzieć na te pytania, musielibyśmy zmienić uprawnienia z

  • Utwórz
  • Pokaż
  • update
  • destroy

Do konwencjonalne

  • post
  • get
  • put
  • Usuń

Chociaż ten przykład pokazuje wszystko zakodowane na twardo, lepszą praktyką jest posiadanie interfejsu zarządzania uprawnieniami, aby mogły być tworzone, odczytywane, aktualizowane i usuwane dynamicznie bez konieczności modyfikowania kodu.

Podoba mi się podejście wtyczek node-acl, ponieważ pozwala na bardzo drobnoziarniste przypisanie uprawnień do ról przy użyciu bardzo prostego i elastycznego api. Tam jest o wiele więcej w ich dokumentacji, mój przykład pokazuje, że jestem z pakietem.

Mam nadzieję, że to pomoże.
 26
Author: Isioma Nnodum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-04 21:17:13

W Expressie możesz dodać obsługę, która łączy się z każdym operatorem (http://expressjs.com/guide.html#passing-route control), gdzie można wykonać walidację warunków wstępnych. Tutaj możesz pobrać rolę dla użytkownika i ograniczyć dostęp na podstawie czasownika HTTP (PUT, DELETE, itp.)lub URL (param('op') to' edit ' lub tak).

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));
  }
});
 3
Author: Jan Jongboom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-22 11:22:42

Napisałem moduł jako nie-jawne routing middleware. Dobrze współpracuje z trasami ekspresowymi.

Gandalf na Githubie

 2
Author: Patrick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-14 08:31:33