Введение
Всем привет!
Сегодня мы поговорим о том, как сделать вашу систему авторизации надежной, гибкой и простой в управлении с помощью библиотеки Casbin. Если вы когда-нибудь задумывались о том, как настроить права доступа в своем приложении, но вас пугала сложность этого процесса, то эта статья для вас. Мы разберем основные понятия и покажем, что настройка авторизации может быть не такой уж и сложной задачей.
Casbin — это мощная и легко расширяемая библиотека для управления доступом, которая поддерживает различные модели контроля доступа. Вот несколько примеров:
-
RBAC (Role-Based Access Control) — модель, основанная на ролях, где права доступа назначаются ролям, а не конкретным пользователям.
-
ABAC (Attribute-Based Access Control) — модель, основанная на атрибутах, где решения принимаются на основе атрибутов пользователя, ресурса, действия и контекста.
-
ACL (Access Control List) — список управления доступом, где каждому ресурсу сопоставляется список пользователей и их прав.
Сегодня мы сосредоточим наше внимание на RBAC, одной из самых популярных и понятных моделей.
Что такое RBAC
RBAC (Role-Based Access Control), или управление доступом на основе ролей, — это модель контроля доступа, в которой права доступа назначаются не конкретным пользователям, а ролям. Пользователи получают права, принимая на себя определенные роли. Эта модель значительно упрощает управление правами доступа в системе, особенно когда пользователей много и их права часто меняются.
Визуальное представление RBAC (я не разобрался как в md
редакторе на забре вставить диаграмму с локальной машины xD, потому можете посмотреть диаграму на моем google drive)
https://drive.google.com/file/d/1kWD5Xds3e3jZh3fkqECBNuqvqLtRP7xu/view?usp=sharing
На диаграмме показаны:
-
Роли:
-
Роль представляет собой набор прав доступа.
-
Например, роль
user
, которая может выполнятьCRUD
с своими ресурсами и читать ресурсы других пользователей.
-
-
Пользователи:
-
Пользователь — это любой субъект (человек или процесс), которому нужно иметь доступ к ресурсам.
-
Пользователям назначаются одна или несколько ролей. Например, пользователь Bob может иметь роль
user
.
-
-
Права:
-
Права определяют, какие действия могут выполняться над какими ресурсами.
-
Например, право
read
может разрешать чтение данных своих или чужих постов.
-
-
Связи:
-
Связи между ролями и правами определяют, какие права принадлежат каким ролям.
-
Связи между пользователями и ролями определяют, какие роли назначены каким пользователям.
-
Создание RBAC модели
Создание модели RBAC с группировками
Casbin использует файл модели для определения структуры контроля доступа. Давайте создадим файл модели rbac-model.conf
:
rbac-model.conf
[request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [role_definition] g = _, _ g2 = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = r.act == p.act && ; проверяем, что action совпадает как в политике, так и в кортеже, который мы получаем в request. g(r.sub, p.sub) && ; это внутрення функция, которая сопоставляет sub с request и сравнивает с ролями пользователя в политики. (g2(p.obj, r.obj) || p.obj == "*") ; мы проверяем, что если req.obj != * (доступ ко всем ресурсам), то выполняется внутрення функция сравнения группировок ресурсов пользователя в политики.
-
request_definition: Определяет формат запроса (кто, что, какое действие).
-
policy_definition: Определяет формат политики.
-
role_definition: Определяет формат ролей и группировок (группы g и g2).
-
policy_effect: Определяет эффект политики (разрешить или запретить).
-
matchers: Определяет логику сопоставления запроса с политиками, включая дополнительные группировки.
По сути мы видим, что у нас есть r (role_definition)
— кортеж, который мы будем передавать с запроса, и есть p (policy_definition)
— политика, о которой мы поговорим в следующем пункте.
Мы объявляем g
и g2
(role_definition)
— это особенность RBAC
. По сути своей это всего лишь группировки, пример так же будет в блоке про политики.
g
отвечает за роли «пользователя». Например у нас есть роль owner
и у него может быть несколько видов доступных для него действий — read, edit, delete
.
g2
— это группировка для ресурсов. Допустим у пользователя Bob
может быть несколько ресурсов, которые будут храниться в группе Bob-Resources
.
Раздел policy_effect
определяет, как Casbin
должен обрабатывать результат сопоставления политики. Он отвечает за то, что происходит, когда один или несколько правил политики применяются к запросу на доступ. Проще говоря, он решает, разрешить или запретить действие, основываясь на правилах, которые были найдены. Таким образом, policy_effect
определяет, что если хотя бы одно правило позволяет доступ, то запрос будет одобрен.
Ну и сам алгоритм проверки — matchers
. Их мы можем настраивать как нашей душе угодно, но в примере приведен пример для RBAC
модели.
Примечание Так же стоит заметить порядок сравнений в
matchers
. Так сделано для того, чтобы увеличить скорость. В случае если у нас произойдет ошибка во время проверки на действие нам не придется выполнять лишнии функции.
Настройка политик доступа
Теперь создадим файл с политиками policy.csv
, в котором определим права доступа и группировки:
policy.csv
<!-- определяем пользователей, даем доступ к группе ресурса и доступ к ролям --> p, alice, admin-res, admin p, bob, bob-res, user p, bob, guest-res, guest p, clare, guest-res, guest <!-- создаем роль crud, чтобы не дублировать имена действий --> g, crud, create g, crud, read g, crud, update g, crud, delete <!-- выдаем ролям действия --> g, admin, crud g, user, crud g, guest, read <!-- создаем группы ресурсов --> g2, all-resources g2, admin-res, all-resource g2, bob-posts g2, bob-friends g2, bob-groups g2, bob-res, bob-posts g2, bob-res, bob-groups g2, bob-res, groups g2, guest-res, all-resource
-
p: Определяют права для ролей.. Например, роль
admin
имеет права crud наadmin-res
. -
g: Определяет отношения ролей. Например,
alice
являетсяadmin
, аbob
являетсяuser
. -
g2: Определяет группировки ресурсов. Например,
all-resources
принадлежат группеadmin-res
иguest-res
Как и было обещано в предыдущем блоке — буду объяснять что да как.
Первым делом определяются политики — их очень легко понять, По сути буквой p
мы указываем, что это будем политика. Далее мы указываем имя пользователя (в настоящем приложении это может быть токен или идентификатор), далее мы указываем ресурсы к которым наш пользователь будем иметь доступ, ну и указываем действие, которые может выполнять пользователь с ресурсами, к которым у него есть доступ.
И так, далее мы видим тот самый role_definition - g
. Мы создаем группировку действий crud
, по сути это можно воспринимать как переменную — мы создаем переменную, чтобы после ее переиспользовать. Чтобы каждому пользователю не назначать каждый раз одинаковые действий мы будем назначать ему группировку. Сейчас покажу почему это сделано именно так: вместо того, чтобы делать так
p, bob, bob-res, create p, bob, bob-res, read p, bob, bob-res, update p, bob, bob-res, delete
мы создали группировку и можем назначать ее любому количеству пользователей
p, den, res, crud p, emily, res, crud p, frank, res, crud
Точно такая же ситуация и с группировками для ресурсов, потому что у нас могут общие ресурсы, могут быть приватные ресурсы и их может быть очень много, поэтому лучше разбить их на группы и подгруппы и выдавать конкретным пользователям.
Интеграция Casbin в приложение
Установка и настройка Casbin
Создадим директория для проекта
mkdir casbin-rbac cd casbin-rbac
Инициализируем приложение и установим зависимость
go mod init casbinrbac go get github.com/casbin/casbin/v2
package main import ( "fmt" "github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2/persist/file-adapter" ) func main() { // так же есть возможность подключить БД адаптеры, смотреть ниже adapter := fileadapter.NewAdapter("policy.csv") // enforcer это основной компонент, который отвечает за // 1. Загрузка модели и политик - загружает модель (rbac-model.conf) и (policy.csv) // 2. Принятие решений о доступе - принимает запросы на доступ // и сопоставляет их с политиками для принятия решения, разрешить или запретить доступ // 3. Управление ролями и пользователями - Позволяет добавлять и удалять пользователей, // назначать роли и управлять правами доступа enforcer, err := casbin.NewEnforcer("rbac-model.conf", a) var ( sub = "bob" obj = "bob-posts" act = "read" ) isAuth, _ := enforcer.Enforce(sub, obj, act) if ok { fmt.Printf("sub %s successfully authorized to %s resource, action - %s", sub, obj, act) } else { fmt.Printf("sub %s not-authorized to %s resource, action - %s", sub, obj, act) } }
Запустим наше приложение и посмотрим что из этого вышло:
go run main.go
Так же `casbin` поддерживает другие виды адаптеров, например `postgres`:
Будем использовать официальный инструмент
go get github.com/casbin/casbin-pg-adapter
Создание БД и миграции
База данны обязательно должна называться casbin и иметь таблицу сasbin_rule
Для начала подними postgres
образ в docker
:
docker run --name casbin -p 5432:5432 -e POSTGRES_PASSWORD=casbin_path -e POSTGRES_USER=casbin_user -e POSTGRES_DB=casbin -d postgres
Вы можете использовать любой инструмент для миграций, я просто оставлю sql
:
create extension if not exists "uuid-ossp";; create table if not exists casbin_rule ( id uuid default gen_random_uuid() primary key, ptype text not null, v0 text not null, v1 text not null, v2 text, v3 text, v4 text, v5 text ); insert into casbin_rule (ptype, v0, v1, v2) values ('p', 'alice', 'admin-res', 'admin'), ('p', 'bob', 'bob-res', 'user'), ('p', 'bob', 'guest-res', 'guest'), ('p', 'clare', 'guest-res', 'guest'), ('g', 'crud', 'create', ''), ('g', 'crud', 'read', ''), ('g', 'crud', 'update', ''), ('g', 'crud', 'delete', ''), ('g', 'admin', 'crud', ''), ('g', 'user', 'crud', ''), ('g', 'guest', 'read', ''), ('g2', 'all-resources', '', ''), ('g2', 'admin-res', 'all-resources', ''), ('g2', 'bob-posts', '', ''), ('g2', 'bob-friends', '', ''), ('g2', 'bob-groups', '', ''), ('g2', 'bob-res', 'bob-posts', ''), ('g2', 'bob-res', 'bob-friends', ''), ('g2', 'bob-res', 'bob-groups', ''), ('g2', 'guest-res', 'all-resources', ''),
Запись в таблицу нужна только для примера нашего приложения. Выполните эти миграции и можете идти дальше.
Создадим адаптер:
package adapter import ( "os" pgadapter "github.com/casbin/casbin-pg-adapter" "github.com/casbin/casbin/v2/persist" ) // Casbin.Adapter должен имплементировать интерфейс persist.Adapter, // который должен реализовать методы для работы с политиками: /** type Adapter interface { // LoadPolicy loads all policy rules from the storage. LoadPolicy(model model.Model) error // SavePolicy saves all policy rules to the storage. SavePolicy(model model.Model) error // AddPolicy adds a policy rule to the storage. // This is part of the Auto-Save feature. AddPolicy(sec string, ptype string, rule []string) error // RemovePolicy removes a policy rule from the storage. // This is part of the Auto-Save feature. RemovePolicy(sec string, ptype string, rule []string) error // RemoveFilteredPolicy removes policy rules that match the filter from the storage. // This is part of the Auto-Save feature. RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error } */ func NewPgCasbinAdapter() (persist.Adapter, error) { dsn := os.Getenv("PG_DSN") return pgadapter.NewAdapter(dsn) }
Конечно же это простой пример того как проходит авторизация
Управление ролями и пользователями
Casbin позволяет легко управлять ролями и пользователями в вашей системе. С его помощью можно добавлять, удалять и изменять роли, а также назначать их пользователям. Давайте рассмотрим основные операции, которые можно выполнять для управления ролями и пользователями.
Добавление пользователей к ролям
Чтобы добавить пользователя к роли, можно использовать метод AddGroupingPolicy
. Это позволяет связывать пользователей с ролями.
package main import ( "fmt" "github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/persist/file-adapter" ) func main() { e, _ := casbin.NewEnforcer("rbac-model.conf", "policy.csv") // Добавление пользователя к роли e.AddGroupingPolicy("charlie", "user") }
В этом примере мы добавляем пользователя charlie
к роли user
.
Удаление пользователей из ролей
Чтобы удалить пользователя из роли, можно использовать метод RemoveGroupingPolicy
.
// Удаление пользователя из роли e.RemoveGroupingPolicy("charlie", "user")
Этот метод удалит связь между пользователем charlie
и ролью user
.
Добавление прав к ролям
Для добавления прав к роли можно использовать метод AddPolicy
.
// Добавление прав к роли e.AddPolicy("editor", "data2", "write")
Этот метод добавляет правило, что роль editor имеет право write на ресурс data2.
Удаление прав у ролей
Для удаления прав у роли можно использовать метод RemovePolicy
.
// Удаление прав у роли e.RemovePolicy("editor", "data2", "write")
Этот метод удаляет правило, что роль editor имеет право write на ресурс data2.
Проверка ролей и прав
Вы можете проверить, к каким ролям принадлежит пользователь и какие права у роли.
// Получение ролей пользователя roles, _ := e.GetRolesForUser("alice") // Получение прав роли permissions, _ := e.GetPermissionsForUser("admin")
Эти методы позволяют узнать, какие роли назначены пользователю alice
и какие права имеет роль admin
.
Полный пример
Давайте соберем всё вместе в одном примере.
package main import ( "fmt" "github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/persist/file-adapter" ) func main() { // Загрузка модели и политик e, _ := casbin.NewEnforcer("rbac-model.conf", "policy.csv") // Добавление пользователя к роли e.AddGroupingPolicy("charlie", "user") // Удаление пользователя из роли e.RemoveGroupingPolicy("charlie", "user") // Добавление прав к роли e.AddPolicy("editor", "data2", "write") // Удаление прав у роли e.RemovePolicy("editor", "data2", "write") // Получение ролей пользователя roles, _ := e.GetRolesForUser("alice") // Получение прав роли permissions, _ := e.GetPermissionsForUser("admin") }
Заключение
Вот и подошел к концу небольшой экскурс по Casbin
, надеюсь, что теперь вы сможете упростить работу с доступами к ресурсам и, может быть, даже сможете принести эту идею в свою команду и получить за это некоторые плюшки.
В целом это весьма несложная тема и с ней достаточно просто разобраться. Надеюсь. что смог кому-то помочь.
Так же Casbin
поддерживает и другие языки, такие как:
-
php
-
nodejs
-
.net
-
python
-
rust
-
java
В ближайшие дни я планирую снять обучающий ролик на ютуб, там я сделаю небольшое API
и покажу на примерах как использовать ролевую модель RBAC
, поэтому если кому-то интересно такое, то предлагаю перейти в мой канал, там я в скором времени анонсирую всю информацию.
ссылка на оригинал статьи https://habr.com/ru/articles/823374/
Добавить комментарий