Многие реализации RBAC (управление доступом на основе ролей) различаются, но основные принципы широко распространены, поскольку они имитируют назначение реальных ролей (должностей). —Онур Йылдырым.

Управление доступом на основе ролей (RBAC) — это метод изменения доступа и привилегий на основе ролей отдельных пользователей или групп пользователей в организации.

RBAC позволяет членам организации иметь доступ только к тем ресурсам, которые им необходимы для выполнения их работы, и ограничивает или запрещает неограниченные привилегии для ресурсов, которые им не принадлежат.

RBAC против ABAC

Управление доступом на основе ролей и управление доступом на основе атрибутов (ABAC) являются типами методов управления доступом, но их подходы различаются. Вариант использования, для которого требуется система RBAC, будет состоять в том, что мы намерены предоставлять привилегии приложению в зависимости от ролей пользователей.

В то время как ABAC предоставляет доступ на основе комбинации атрибутов, то есть атрибутов пользователя, атрибутов ресурсов, атрибутов, связанных с системой или приложением, к которым осуществляется доступ, атрибутов среды и т. д. Например, атрибуты пользователя могут включать биоданные, уникальные идентификаторы, роль, уровень допуска и т. д.

Предыстория

В недавнем проекте перед моей командой была поставлена ​​задача реализовать пользовательскую структуру управления доступом на основе ролей для MongoDB (NoSQL DB) с использованием схемы ORM mongoose. В этой структуре управления доступом мы рассмотрим 3 объекта:

Контекст реализации

  • У пользователя есть роль
  • Приложение определило Ресурсы и,
  • Роль имеет привилегии и разрешения на ресурсы

давайте напишем схемы мангустов для наших коллекций 😄

Схема

resources.models.js

/* RBAC - role-based access control
 first create roles; role =[ "user", "guest", "organization",  "superadmin" "globalsuperadmin"]
 next, create resouuce, add their roles_id and permmissions
 finally create users and indcate thier roles
*/
const mongooseClient = app.get('mongooseClient');
    const { Schema } = mongooseClient;
const resources = new Schema({
      name: { type: String, required: true },
      slug: { type: String, required: true },
      resources_roles: [{
        roles_id: { type: Schema.Types.ObjectId, ref : 'Roles' },
        roles_name: { type:  String },
        create: { type: Boolean },
        delete: { type: Boolean },
        update: { type: Boolean },
        read: { type: Boolean },
      }]
    }, {
      timestamps: true
    });
return mongooseClient.model('resources', resources);

roles.models.js

const mongooseClient = app.get('mongooseClient');
    const { Schema } = mongooseClient;
module.exports = function (app) {
    const mongooseClient = app.get('mongooseClient');
    const { Schema } = mongooseClient;
    const roles = new Schema({
      name: { type: String, required: true },
      slug: { type: String, required: true },
    }, {
      timestamps: true
    });
return mongooseClient.model('roles', roles);
  };

users.models.js

const mongooseClient = app.get('mongooseClient');
    const { Schema } = mongooseClient;
module.exports = function (app) {
    const mongooseClient = app.get('mongooseClient');
    const { Schema } = mongooseClient
    const users = new mongooseClient.Schema({
      email: {type: String, unique: true, lowercase: true},
      password: { type: String },
      first_name: { type: String },
      last_name: { type: String },
      roles: { type: Schema.Types.ObjectId, ref : 'Roles' },
}, {
      timestamps: true
    });
return mongooseClient.model('users', users);
  };

Теперь, когда вам нужны разрешения роли на ресурс, вы просто ищете role_id и resource_id и проверяете, для каких разрешений установлено значение true в resources collection.

ПО промежуточного слоя авторизации

users.post('/', getAuth, someMethod)

Предполагая, что у вас есть какой-то токен в запросе, который идентифицирует пользователя, делающего сообщение, и прикрепляя экземпляр пользователя к объекту запроса, вы можете сделать это:

// pseudo code
getAuth = function (req, res, next) {
  if(req.user) {
// query to get the user role's  permissions for a resource
    if(token){
    // handle jwt token authenticity and decrypt payload
// get permission handler
    db.getPerms({ role_id: req.user.role_id, resource_id: req.resource.id})
    .then((perms) => {
       var allow = false;
       // mapping of methods to permissions
       perms.forEach(function(perm){
           if (req.method == "POST" && perms.create) allow = true;
           else if (req.method == "GET" && perms.read) allow = true;
           else if (req.method == "PUT" && perms.write) allow = true;
           else if (req.method == "DELETE" && perm.delete) allow = true;
})
       if (allow) next();
       else {
            res.status(403).send({error: 'access denied'});
        }
    })
    .catch((err)=> {
       //handle your reject and catch here
    })
} else{
    res.status(400).send({error: 'invalid token'})
}

Это некий псевдокод, показывающий, как можно написать промежуточное ПО аутентификации.

Это не самый оптимизированный фреймворк для реализации RBAC, поэтому я с нетерпением жду ваших отзывов 😄!!

Спасибо за аудиторию, и я надеюсь, что вы нашли эту статью полезной 🤗. Не стесняйтесь обращаться ко мне на Github, Twitter и LinkedIn. Ставьте лайк, комментируйте и делитесь 😌.

Первоначально опубликовано на https://blog.nextwebb.tech.