У вас включен AdBlock или иной блокировщик рекламы.

Пожалуйста, отключите его, доход от рекламы помогает развитию сайта и появлению новых статей.

Спасибо за понимание.

В другой раз
DevGang блог о програмировании
Авторизоваться

Как сохранить инстанс goRBACH

goRBAC  предоставляет довольно облегченную реализацию управления доступом (RBAC) по ролям в Голанге. Вся информация о привилегиях (роли, родители и разрешения), как правило,  сохраняется в постоянном хранилище, к примеру в базе данных, файлах или облачном хранилище. В этом посте мы с вами кратко обсудим, как загрузить экземпляр goRBAC из постоянного хранилища и как сохранить экземпляр обратно. Чтобы нам было проще, в качестве постоянного хранилища будем использовать файл JSON.

Подготавливаемся / Определяем роли 

Представим, что у нас есть 3 роли: Editor, Photographer and Chief Editor.. Каждая роль имеет следующих родителей и разрешения:

Role

Parents

Permissions

editor

NULL

add-text, edit-text, insert-photo

photographer

NULL

add-photo, edit-photo

chief-editor

editor, photographer

del-text, del-photo

Преобразуем таблицы в два формата JSON. Первый сохраняет данные о ролях (`role.json`), а второй информацию о наследовании (` attribute.json`):

{"editor":["add-text","edit-text","insert-photo"],"photographer":["add-photo","edit-photo"],"chief-editor":["del-text","del-photo"]}
{"chief-editor":["editor","photographer"]}

Мне кажется, здесь все достаточно очевидно и ясно, поэтому я сейчас не стану тратить время на объяснения. Однако, если у вас есть какие-либо вопросы об этой конвертации, прощу вас под кат в комментарии.

Загрузка из файла JSON

Загрузка информации и создание экземпляра goRBAC довольно просто сделать.

Прежде всего, откройте файл JSON и загрузите все данные в map экземпляр.

// map[RoleId]PermissionIds
var jsonRoles map[string][]string
// map[RoleId]ParentIds
var jsonInher map[string][]string
// Load roles information
if err := LoadJson("roles.json", &jsonRoles); err != nil {
    log.Fatal(err)
}
// Load inheritance information
if err := LoadJson("inher.json", &jsonInher); err != nil {
    log.Fatal(err)
}

А теперь мы можем начать создавать экземпляр goRBAC. Чтобы это сделать, потребуется проделать всего 3 шага.

Прежде всего, инициализируйте экземпляр:

rbac := gorbac.New()
permissions := make(gorbac.Permissions)

И затем мы можем сделать роли `Role (s)` и добавить их в экземпляр goRBAC.

// Build roles and add them to goRBAC instance
for rid, pids := range jsonRoles {
    role := gorbac.NewStdRole(rid)
    for _, pid := range pids {
        _, ok := permissions[pid]
        if !ok {
            permissions[pid] = gorbac.NewStdPermission(pid)
        }
        role.Assign(permissions[pid])
    }
    rbac.Add(role)
}

После этого мы можем назначить отношения наследования между ролями.

// Assign the inheritance relationship
for rid, parents := range jsonInher {
    if err := rbac.SetParents(rid, parents); err != nil {
        log.Fatal(err)
    }
}

Общие use-кейсы

После загрузки всей информации и экземпляром goRBAC под рукой , мы можем начать проверять привилегии.

Вы можете узнать, как это делать здесь.

Сохранение обратно в файл JSON

Если мы добавим несколько новых ролей и разрешений или изменим отношения между ролями, то запись изменений обратно в постоянное хранилище будет довольно существенной.

Самый простой способ - использовать вспомогательную функцию `Walk`

// Persist the change
// map[RoleId]PermissionIds
jsonOutputRoles := make(map[string][]string)
// map[RoleId]ParentIds
jsonOutputInher := make(map[string][]string)
SaveJsonHandler := func(r gorbac.Role, parents []string) error {
    // WARNING: Don't use gorbac.RBAC instance in the handler,
    // otherwise it causes deadlock.
    permissions := make([]string, 0)
    for _, p := range r.(*gorbac.StdRole).Permissions() {
        permissions = append(permissions, p.ID())
    }
    jsonOutputRoles[r.ID()] = permissions
    jsonOutputInher[r.ID()] = parents
    return nil
}
if err := gorbac.Walk(rbac, SaveJsonHandler); err != nil {
    log.Fatalln(err)
}
 
// Save roles information
if err := SaveJson("new-roles.json", &jsonOutputRoles); err != nil {
    log.Fatal(err)
}
// Save inheritance information
if err := SaveJson("new-inher.json", &jsonOutputInher); err != nil {
    log.Fatal(err)
}

Стоит упомянуть кое-что: хоть это closure, НЕ используйте экземпляр goRBAC в обработчике(handler). Это загонит вас в тупик. Ведь основная концепция `WalkHandler` в получении информации из экземпляра goRBAC, который является readonly процессом для него. У вас нет доступа к экземпляру goRBAC без каких либо изменений.

Заключение

goRBAC следует основной идее Go -  «меньше», значит экспоненциально «больше» (прим. переводчика — less is exponentially more) и вдохновлен «Чистой архитектурой». Поэтому такие сложные функции, как интерфейс СУБД, интерфейс NoSQL или аутентификация, не появляются в ядре. Хотя `Helper` является важной частью, облегчающей использование goRBAC.

#Golang