Метод авторизации на основе групп/правил в node.js и express.js
Каковы хорошие стратегии для авторизации на основе ролей в express.js? Особенно с экспресс-ресурсом?
С Express-resource никаких обработчиков нет, поэтому я думаю, что есть три варианта:
- Использовать промежуточное программное обеспечение
- Передайте функцию авторизации ресурсу и проверьте каждый запрос ресурса отдельно
- Проверить авторизацию с каждым запросом сразу после аутентификации
Есть ли другие решения?
Авторизация на основе групп/ролей - довольно античный подход. Существуют ли новые методы контроля доступа? Если нет, как можно применить авторизацию на основе ролей к node.js? Где хранить отношения группового правила (с NoSQL/CouchDB/Redis)?
В качестве примера, структура:
/
/forums
/forums/threads
Каждый ресурс с индексом, новым, создаёт, показывает, редактирует обновление и уничтожает. Некоторые люди могут редактировать/удалять и т.д. Темы и форумы, некоторые люди не должны.
Ответы
Ответ 1
Connect-role довольно хороший, простой и документация тоже очень понятная.
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');
}
Ответ 2
Я бы сказал, что это сложно решить с помощью экспресс-ресурса, поскольку он не позволяет использовать связующее ПО, специфичное для маршрута (по крайней мере, не в чистом виде).
Я бы выбрал аналогичный макет, как модуль экспресс-ресурсов, но проложил его с помощью обычного старого экспресса. Что-то вроде этого:
// 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
ОБНОВЛЕНИЕ:. Продолжались обсуждения относительно промежуточного ПО, специфичного для маршрута, в экспресс-ресурсе, например. здесь. По-видимому, преобладающее представление состоит в том, чтобы иметь массив для каждого действия, например:
var forums = {
index: [ requireRole('foo'), function(req, res, next) { ... } ]
};
Вы можете просмотреть запросы на растяжение и посмотреть, есть ли что-нибудь, что вы могли бы использовать. Конечно, я полностью понимаю это, если вам это не нравится. Я уверен, что в будущем мы увидим что-то подобное в экспресс-ресурсе.
Единственное другое решение, о котором я могу думать, - это ответ на вопрос Джона Джунгбома, который должен был собрать ресурсы с помощью экспресс-ресурса, но у него есть "внешнее" связующее ПО, что-то вроде:
app.delete('*', requireRole('admin')); // Only admins are allowed to delete anything
app.put('/forums/*', requireRole('moderator')); // Only moderators are allowed to update forums
Но я сожалею, что это утечка URL-адресов повсюду.
Ответ 3
Я изучаю тот же вопрос и сталкиваюсь с несколькими хорошими модулями. Я сосредоточен на пакете node -acl, который можно найти здесь. https://github.com/optimalbits/node_acl.
Этот пакет, по-видимому, реализовал шаблон ACL очень понятным образом и предоставил способы легко интегрировать его в ваше приложение node/express.
Во-первых, вы захотите определить свои ресурсы, роли и разрешения.
Например, ресурсы могут быть:
/
/forums
/forums/threads
Роли могут быть
public
admin
user
john
jane
В этом примере роли john и jane могут сопоставляться с реальными учетными записями пользователей, но они наследуют все разрешения пользователя.
Права на ресурсы
- создать
- Показать
- update
- уничтожить
Или ваши стандартные операции CRUD.
Теперь, когда они были определены, мы можем взглянуть на то, как это будет выглядеть для установки acl с помощью node -acl. Эти примечания получены из документации
импортировать пакет
var acl = require('acl');
Настройте свой сервер. Мое приложение использует mongodb, но пакет node -acl поддерживает другие механизмы хранения
acl = new acl(new acl.mongodbBackend(dbInstance, prefix));
Мое приложение использует mongoose, поэтому dbInstance будет заменен mongoose.connection.db
Теперь добавим наши роли в ACL. В node -acl роли создаются путем предоставления им разрешений. Это похоже на убийство двух зайцев одним камнем (ни один из птиц не пострадал)
acl.allow('admin', ['/', '/forum', '/forum/threads'], '*');
acl.allow('public', ['/', '/forum', '/forum/threads'], 'show');
acl.allow('user', ['/', '/forum', '/forum/threads'], ['create', 'show']);
Предположим, что новый ресурс создан john, мы добавим новую запись, которая позволит john также обновлять и удалять этот ресурс.
acl.allow('john', ['/forum/threads/abc123'], ['update', 'delete']);
Мое приложение также использует экспресс, поэтому я буду использовать подход промежуточного программного обеспечения маршрутизации для проверки маршрутов. В моей конфигурации маршрутизации я бы добавил строку
В большинстве экспресс-конфигураций это выглядит как 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) {...});
Если параметры не переданы, это проверяет, разрешена ли роль, определенная в req.userId, выполнять метод http на идентифицированном ресурсе, но маршрут.
В этом примере метод http - это сообщение, но он будет делать то же самое для каждого http idenitified в вашей конфигурации.
Возникает вопрос о разрешениях, определенных ранее. Чтобы ответить на эти вопросы, нам нужно было бы изменить разрешения от
- создать
- Показать
- update
- уничтожить
К обычным
- после
- получить
- поместить
- удалить
Хотя этот пример показывает все жестко запрограммированные, лучше использовать интерфейс управления для своих разрешений, чтобы их можно было создавать, читать, обновлять и удалять динамически без необходимости изменения кода.
Мне нравится подход плагинов node -acl, так как он позволяет назначать очень мелкие грань разрешений с использованием очень простого и гибкого api. В их документации гораздо больше, мой пример показывает, что я с пакетом.
Надеюсь, это поможет.
Ответ 4
В express вы можете добавить обработчик, который подключается к каждому оператору (http://expressjs.com/guide.html#passing-route control), где вы можете сделать предварительную проверку. Здесь вы можете получить роль для пользователя и ограничить доступ на основе HTTP-глагола (PUT, DELETE и т.д.) Или URL-адреса (param('op')
is "edit" или так).
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));
}
});
Ответ 5
Я написал модуль как неявное промежуточное ПО маршрутизации. Хорошо работает с экспресс-маршрутами.
Gandalf on GitHub
Ответ 6
Вы можете попробовать Casbin: https://casbin.org/, у него есть версия Node.js. Он также имеет промежуточное программное обеспечение Express.js под названием express-authz
: https://casbin.org/docs/en/middlewares