/
rbac.go
170 lines (149 loc) · 4.01 KB
/
rbac.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
goRBAC provides a lightweight role-based access control implementation
in Golang.
For the purposes of this package:
* an identity has one or more roles.
* a role requests access to a permission.
* a permission is given to a role.
Thus, RBAC has the following model:
* many to many relationship between identities and roles.
* many to many relationship between roles and permissions.
* roles can have parent roles.
*/
// rbac := middleware.NewRbac()
// m.Map(rbac)
//
// m.Get("/article/edit", func(c *middleware.Context, rbac *middleware.Rbac) {
// ok := rbac.IsGranted("editor", "edit.article",
// func(role, permission string, rbac *middleware.Rbac) bool {
// return article.Owner == User.Id
// })
// if ok {
// fmt.Println("have permission....")
// } else {
// fmt.Println("not have permission....")
// }
// c.HTML(200, "index", c.Data)
// })
//
//
package middleware
import (
"sync"
)
const (
bufferSize = 256
)
// Assertion function supplies more fine-grained permission controls.
type AssertionFunc func(string, string, *Rbac) bool
// Export RBAC to a structure data
type Map map[string]RoleMap
// RBAC
type Rbac struct {
mutex sync.RWMutex
roles map[string]Role
factory RoleFactoryFunc
}
// Return a RBAC structure with a specific factory function.
// Role structure will be generated by the function.
func NewWithFactory(factory RoleFactoryFunc) *Rbac {
rbac := &Rbac{
roles: make(map[string]Role, bufferSize),
factory: factory,
}
return rbac
}
// Return a RBAC structure.
// The default role structure will be used.
func NewRbac() *Rbac {
return NewWithFactory(newBaseRole)
}
// Restore rbac from a map, use factory for your own data structure
func RestoreWithFactory(data Map, factory RoleFactoryFunc) *Rbac {
rbac := NewWithFactory(factory)
for role, value := range data {
rbac.Add(role, value[PermissionKey], value[ParentKey])
}
return rbac
}
// Restore rbac from a map, a default role implamentation used
func Restore(data Map) *Rbac {
return RestoreWithFactory(data, newBaseRole)
}
// Set a role with `name`. It has `permissions` and `parents`.
// If the role is not existing, a new one will be created.
// This function will cover role's orignal permissions and parents.
func (rbac *Rbac) Set(name string, permissions []string, parents []string) {
rbac.mutex.Lock()
defer rbac.mutex.Unlock()
role := rbac.getRole(name)
role.Reset()
for _, p := range permissions {
role.AddPermission(p)
}
for _, pname := range parents {
role.AddParent(pname)
}
}
// Add a role with `name`. It has `permissions` and `parents`.
// If the role is not existing, a new one will be created.
// This function will add new permissions and parents to the role,
// and keep orignals.
func (rbac *Rbac) Add(name string, permissions []string, parents []string) {
rbac.mutex.Lock()
defer rbac.mutex.Unlock()
role := rbac.getRole(name)
for _, p := range permissions {
role.AddPermission(p)
}
for _, pname := range parents {
role.AddParent(pname)
}
}
// Remove a role.
func (rbac *Rbac) Remove(name string) {
rbac.mutex.Lock()
defer rbac.mutex.Unlock()
delete(rbac.roles, name)
}
// Internal getRole
func (rbac *Rbac) getRole(name string) Role {
role, ok := rbac.roles[name]
if !ok {
role = rbac.factory(rbac, name)
rbac.roles[name] = role
}
return role
}
// Return a role or nil if not exists.
func (rbac *Rbac) Get(name string) Role {
rbac.mutex.RLock()
defer rbac.mutex.RUnlock()
role, ok := rbac.roles[name]
if !ok {
return nil
}
return role
}
// Test if the `name` has `permission` in the `assert` condition.
func (rbac *Rbac) IsGranted(name, permission string,
assert AssertionFunc) bool {
rbac.mutex.RLock()
defer rbac.mutex.RUnlock()
if assert != nil && !assert(name, permission, rbac) {
return false
}
if role, ok := rbac.roles[name]; ok {
return role.HasPermission(permission)
}
return false
}
// Dump RBAC
func (rbac *Rbac) Dump() Map {
m := make(Map)
for _, role := range rbac.roles {
roleMap := RoleToMap(role)
m[role.Name()] = roleMap
}
return m
}