Что такое RBAC? Управление доступом на основе ролей (RBAC) в Casbin
Что такое RBAC?
Управление доступом на основе ролей (RBAC) предоставляет разрешения ролям, а не отдельным пользователям, и назначает каждому пользователю одну или несколько ролей. Чтобы новый сотрудник мог выполнять свою работу, вы назначаете ему роль, например editor или billing; чтобы изменить права всех редакторов, достаточно изменить эту роль один раз.
RBAC состоит из трех частей:
- Пользователи: люди или сервисы, отправляющие запросы.
- Роли: именованные должностные функции, такие как
admin,editorилиviewer. - Разрешения: действие над ресурсом, например
editдля/articles.
Запрос разрешен, если одна из ролей пользователя обладает требуемым разрешением. Роли также могут наследовать права от других ролей: если editor наследует от viewer, редакторы получают все возможности зрителей. Концепция RBAC была формализована NIST в 1990-х годах; семейство моделей RBAC96 описывает варианты: плоские роли, иерархии ролей и ограничения. См. RBAC vs. RBAC96, чтобы узнать, как Casbin отображает эти модели.
Минимальная модель и политика RBAC в Casbin:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
p, editor, article, edit
p, viewer, article, read
g, editor, viewer
g, alice, editor
g, bob, viewer
alice может редактировать и читать статьи (editor наследует viewer); bob может только читать их.
RBAC против ABAC: RBAC легко аудировать, но он не позволяет сказать "только свои записи", не создавая отдельную роль для каждой записи. ABAC добавляет условия по атрибутам, таким как владелец или время суток, и большинство приложений комбинируют оба подхода. Выбор модели управления доступом сравнивает ACL, RBAC, ABAC и ReBAC на одном примере.
Руководства: добавьте RBAC в веб-API с помощью Go и Gin, Node.js и Express, NestJS, Python и FastAPI, Java и Spring Boot, Rust или gRPC. Вы также можете попробовать примеры RBAC в онлайн-редакторе.
Определение ролей
Секция [role_definition] определяет отношения наследования ролей RBAC. Casbin может одновременно работать с несколькими системами ролей RBAC: одной для пользователей (с наследованием ролей) и, опционально, другой для ресурсов. Каждая из них независима.
Эта секция необязательна; опустите её, если вы не используете RBAC.
[role_definition]
g = _, _
g2 = _, _
Здесь g и g2 — две системы ролей; _, _ означает, что у каждой из них две стороны (например, пользователь и роль). Используй те только g для ролей пользователей; добавьте g2, если ресурсы также имеют роли. Примеры: rbac_model.conf, rbac_with_resource_roles_model.conf.
Соответствия «пользователь–роль» (и «ресурс–роль») хранятся в политике, например:
p, data2_admin, data2, read
g, alice, data2_admin
Таким образом, alice имеет роль data2_admin. Casbin трактует все имена как строки (пользователь, ресурс или роль).
Используйте роль в матчере:
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
Таким образом, запрос разрешается только в том случае, если субъект запроса имеет роль, указанную в политике.
- Casbin только хранит и оценивает соответствия «пользователь–роль» (и «ресурс–роль»); он не проверяет существование пользователей или ролей. Это задача аутентификации.
- Не используйте одно и то же имя для пользователя и роли (например, пользователь
aliceи рольalice), так как Casbin не сможет их различить. При необходимости используйте префикс (например,role_alice). - Наследование ролей является транзитивным и неограниченным: если A имеет роль B, а B имеет роль C, то A фактически имеет роль C.
Субъект в политике обычно называется sub и указывается первым. В Go-версии Casbin можно использовать другие имена и порядок; в этом случае после создания эфорсера необходимо вызвать e.SetFieldIndex("p", constant.SubjectIndex, index), чтобы такие API, как DeleteUser, использовали правильный столбец.
# `subject` here is for sub
[policy_definition]
p = obj, act, subject
e.SetFieldIndex("p", constant.SubjectIndex, 2) // index starts from 0
ok, err := e.DeleteUser("alice") // without SetFieldIndex, it will raise an error
Именованные системы ролей и зависимости разрешений
g, g2, g3, ... — это независимые системы ролей. Каждая из них определяет граф, к которому матчер обращается по тому же имени; g2 не является встроенной связью «разрешение зависит от разрешения». Строка вида g2, edit, read — это просто ребро графа: она влияет на решение только если матчер вызывает g2(...).
Это важно, когда ваш каталог разрешений содержит зависимости, например, «редактирование подразумевает чтение», поэтому роль, имеющая право на редактирование, должна также иметь право на чтение. Есть два чистых способа смоделировать это.
Используйте наследование ролей, если зависимость является частью авторизации. Назначьте каждой группе разрешений роль и позвольте ролям наследовать друг друга:
p, editor, article, edit
p, viewer, article, read
g, editor, viewer
g, alice, editor
alice может читать, потому что editor наследует viewer; здесь g2 не участвует.
Используйте отдельный граф g2, если сама зависимость должна быть в политике. Матчер определяет смысл:
[role_definition]
g = _, _
g2 = _, _
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && (r.act == p.act || g2(p.act, r.act))
p, admin, article, write
g2, write, read
g, alice, admin
Запрос alice, article, read совпадает со строкой p, admin, article, write, потому что g2(write, read) истинно: write является дочерним элементом read, в том же направлении, что и ребра g. Строки g2 сами по себе ничего не предоставляют и не проверяются Casbin; вы определяете направление и смысл каждого ребра, тогда как Casbin применяет ту же транзитивную иерархию, что и для g.
Если зависимость является только метаданными каталога — скажем, редактору следует автоматически выбирать "read" в административном интерфейсе, когда кто-то отмечает "edit" — храните её в каталоге разрешений и разворачивайте в строки p, g или g2 при генерации политики. Casbin не нужно хранить данные, которые никогда не оцениваются. Политика также не обязана находиться в CSV-файле: адаптер может загружать сгенерированные строки из базы данных или из вашего YAML/JSON каталога, сохраняя каталог как источник истины. См. Адаптеры для API адаптеров.
Иерархия ролей
Casbin реализует иерархию ролей в стиле RBAC1: если alice имеет role1, а role1 имеет role2, то alice фактически имеет role2 и её разрешения.
Глубина иерархии определяет количество уровней наследования, которые вы разрешаете. Менеджер ролей по умолчанию использует максимальную глубину 10 (настраивается), поэтому пользователь может наследовать до 10 уровней ролей.
// NewRoleManager is the constructor for creating an instance of the
// default RoleManager implementation.
func NewRoleManager(maxHierarchyLevel int) rbac.RoleManager {
rm := RoleManager{}
rm.allRoles = &sync.Map{}
rm.maxHierarchyLevel = maxHierarchyLevel
rm.hasPattern = false
return &rm
}
Различи е между пользователями и ролями
В Casbin пользователи и роли представлены строками. В плоской модели RBAC (без иерархии ролей) методы GetAllSubjects() и GetAllRoles() возвращают левую и правую части правил g (часто это пользователи и роли). При наличии иерархии одно и то же имя может встречаться и как пользователь, и как роль; если ваше приложение не отслеживает различие между ними, используйте соглашение об именовании (например, префикс role::) и проверяйте его при интерпретации результатов.
Неявные роли и разрешения
Роли и разрешения, унаследованные через иерархию (а не только назначенные напрямую), называются неявными. Используйте GetImplicitRolesForUser() и GetImplicitPermissionsForUser(), чтобы включить их; методы GetRolesForUser() и GetPermissionsForUser() возвращают только прямые назначения. См. GitHub #137.
Сопоставление с шаблонами в RBAC
См. RBAC with pattern.
Менеджер ролей
См. Role managers для настройки управления ролями.
Comments are powered by giscus and GitHub Discussions. They load from giscus.app and GitHub only after you click the button below.