Thoughs on goRBAC

2017-01-07 19:00:04  mikespook
阅读 49 次  0 条评论  收藏

Code refactoring is not an easy job, but it has to be done in most of the times. I just completed the lightweight role based access control library: goRBAC’s refactoring. There are some feedbacks and questions about the design and usage. I think it would be better writing something to share some design ideas and practice principles which will make things easier.

rbac

The master branch of current goRBAC’s source code is intended to be Version 2. While the previous version has been tagged as Version 1 with the v1.dev branch on Github. And this article will only discuss Version 2 (the master branch).

The new design separates goRBAC into 3 parts: core, interfaces & implements, and helper functions.

The core is the major part of goRBAC and manages inheritance relationship of roles. It contains only one struct `RBAC` with 8 methods. It’s easy to understand and use. What you need is reading the document.

`Role` is the only interface directly communicating with `RBAC`. It has two methods: `Id` returns the identity of a role and `Permit` checks if the permission is permitted to a role. For example, you can implement a Role named `God` and has all permissions as the God.

type God struct {}

func(g *God) Id() string {
    return "God"
}

func(g *God) Permit(p Permission) bool {
    return true
}

For making things easier, goRBAC has a built-in role `StdRole` which can be used in a real-life application and also be a good example for anyone who want to write their own `Role` implementation. Moreover, when you implement your own `Role`, struct embedding can be your good friend.

Eg.,

type MyOwnRole struct {
    gorbac.StdRole
    // extra fields
}
// extra functions

One thing is worth to be noticed, some methods in `Role` like AssignPermission, RevokePermission, Permissions etc. has been removed from the interface. Despite those methods don’t have any affection with `Role` and `RBAC`, they originally defined as a standard API and designed for some data persistence task. I decided to remove them after I joined “Go 1.6 Global Release Party – Auckland Zone” with some great discussions. “Less is exponentially more” again!

Another important interface is `Permission` which is only communicating with `Role`. It also has two methods: `Id` and `Match`. `Id` is the identity of a permission. `Match` is used to detect if current permission matches another one.

The library also supplies two built-in structs for `Permission`.

First one is `StdPermission` which uses `Id` to detect if two permissions are matching.

Another one is `LayerPermission` which supports multi-layers matching and can be very useful to design something like access management of control panels. To be exact, permission “admin” matches “admin:article” and “admin:article:delete”; “admin:article” matches “admin:article:delete”, but you will get a negative result by reversing matching.

And when you have some “hard mode” access control, implementing your own `Permission` is a good idea.

Eg.,

type FuzzPermission struct {
    IdStr string
}

func(f *FuzzPermission) Id() string {
    return f.IdStr
}

func(f *FuzzPermission) Permit(p Permission) bool {
    if f.IdStr == p.Id() { // exactly matched
        return true
    }
    q, ok := p.(*FuzzPermission)
    if !ok { // Not same type
        return false
    }
    return strings.Contains(f.IdStr, p.Id())
}

Well, I’m not sure what circumstance will use this kind of permissions, but you can have it.

本文来自:mikespook 的博客

感谢作者:mikespook

查看原文:Thoughs on goRBAC

0条评论

文章点评:

(您需要 登录 后才能评论 没有账号 ?)
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet