權限框架casbin
1.概述
Casbin是一個強大的、高效的開源訪問控制框架,其權限管理機制支持多種訪問控制模型。
Casbin支持以下編程語言:
- Casbin可以做到:
- 支持自定義請求的格式,默認的請求格式爲
{subject, object, action}
。- 具有訪問控制模型model和策略policy兩個核心概念。
- 支持RBAC中的多層角色繼承,不止主體可以有角色,資源也可以具有角色。
- 支持超級用戶,如
root
或Administrator
,超級用戶可以不受授權策略的約束訪問任意資源。- 支持多種內置的操作符,如
keyMatch
,方便對路徑式的資源進行管理,如/foo/bar
可以映射到/foo*
- Casbin不能做到:
- 身份認證 authentication(即驗證用戶的用戶名、密碼),casbin只負責訪問控制。應該有其他專門的組件負責身份認證,然後由casbin進行訪問控制,二者是相互配合的關係。
- 管理用戶列表或角色列表。 Casbin 認爲由項目自身來管理用戶、角色列表更爲合適, 用戶通常有他們的密碼,但是 Casbin 的設計思想並不是把它作爲一個存儲密碼的容器。 而是存儲RBAC方案中用戶和角色之間的映射關係
github:https://github.com/casbin/casbin
docs:https://casbin.org/docs/zh-CN/overview
2.工作原理
在 Casbin 中, 訪問控制模型被抽象爲基於 PERM (Policy, Effect, Request, Matcher) 的一個文件。 因此,切換或升級項目的授權機制與修改配置一樣簡單。
PERM模型
PERM(Policy, Effect, Request, Matchers)模型很簡單, 但是反映了權限的本質 – 訪問控制
- Policy: 定義權限的規則
- Effect: 定義組合了多個 Policy 之後的結果, allow/deny
- Request: 訪問請求, 也就是誰想操作什麼
- Matcher: 判斷 Request 是否滿足 Policy
[外鏈圖片轉存失敗(img-ys2XIpxc-1565944147357)(C:\Users\Todd\AppData\Roaming\Typora\typora-user-images\1565593950617.png)]
Module File 語法
casbin 是基於 PERM 的, 所有 model file 中主要就是定義 PERM 4 個部分
1.Request definition
[request_definition]
r = sub, obj, act
分別表示 request 中的
- accessing entity (Subject)
- accessed resource (Object)
- the access method (Action)
2.Policy definition
[policy_definition]
p = sub, obj, act
p2 = sub, act
定義的每一行稱爲 policy rule, p, p2 是 policy rule 的名字. p2 定義的是 sub 所有的資源都能執行 act
3.Policy effect
[policy_effect]
e = some(where (p.eft == allow))
上面表示有任意一條 policy rule 滿足, 則最終結果爲 allow
4.Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
定義了 request 和 policy 匹配的方式, p.eft 是 allow 還是 deny, 就是基於此來決定的
5.Role
[role_definition]
g = _, _
g2 = _, _
g3 = _, _, _
g, g2, g3 表示不同的 RBAC 體系, _, _ 表示用戶和角色 _, _, _ 表示用戶, 角色, 域
您可以通過組合可用的模型來定製您自己的訪問控制模型。 例如,您可以在一個model中獲得RBAC角色和ABAC屬性,並共享一組policy規則。
Casbin中最基本、最簡單的model是ACL。ACL中的model CONF爲:
# Request definition
[request_definition]
r = sub, obj, act
# Policy definition
[policy_definition]
p = sub, obj, act
# Policy effect
[policy_effect]
e = some(where (p.eft == allow))
# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
ACL model的示例policy如下:
p, alice, data1, read
p, bob, data2, write
這表示:
- alice可以讀取data1
- bob可以編寫data2
Model存儲
- 從 .CONF 文件中加載 model
e := casbin.NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
- 從代碼加載 model
// Initialize the model from Go code.
m := casbin.NewModel()
m.AddDef("r", "r", "sub, obj, act")
m.AddDef("p", "p", "sub, obj, act")
m.AddDef("g", "g", "_, _")
m.AddDef("e", "e", "some(where (p.eft == allow))")
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act")
// Load the policy rules from the .CSV file adapter.
// 使用自己的 adapter 替換。
a := persist.NewFileAdapter("examples/rbac_policy.csv")
// 創建一個 enforcer。
e := casbin.NewEnforcer(m, a)
- 從字符串加載的 model(推薦)
// Initialize the model from a string.
text :=
`
[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
`
m := NewModel(text)
// Load the policy rules from the .CSV file adapter.
// Replace it with your adapter to avoid files.
a := persist.NewFileAdapter("examples/rbac_policy.csv")
// Create the enforcer.
e := casbin.NewEnforcer(m, a)
這種方法的優點是您不需要維護模型文件
Casbin API
//全局變量 e是執行者實例
e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
//獲取當前策略中顯示的主題列表
allSubjects := e.GetAllSubjects()
//獲取當前命名策略中顯示的主題列表
allNamedSubjects := e.GetAllNamedSubjects("p")
//獲取當前策略中顯示的對象列表
allObjects := e.GetAllObjects()
//獲取當前命名策略中顯示的對象列表
allNamedObjects := e.GetAllNamedObjects("p")
//獲取當前策略中顯示的操作列表
allActions := e.GetAllActions()
//獲取當前命名策略中顯示的操作列表
allNamedActions := e.GetAllNamedActions("p")
//獲取當前策略中顯示的角色列表
allRoles = e.GetAllRoles()
//獲取當前命名策略中顯示的角色列表
allNamedRoles := e.GetAllNamedRoles("g")
//獲取策略中的所有授權規則
policy = e.GetPolicy()
//獲取策略中的所有授權規則,可以指定字段篩選器
filteredPolicy := e.GetFilteredPolicy(0, "alice")
//獲取命名策略中的所有授權規則
namedPolicy := e.GetNamedPolicy("p")
//獲取命名策略中的所有授權規則,可以指定字段過濾器
filteredNamedPolicy = e.GetFilteredNamedPolicy("p", 0, "bob")
//獲取策略中的所有角色繼承規則
groupingPolicy := e.GetGroupingPolicy()
//獲取策略中的所有角色繼承規則,可以指定字段篩選器
filteredGroupingPolicy := e.GetFilteredGroupingPolicy(0, "alice")
//獲取策略中的所有角色繼承規則
namedGroupingPolicy := e.GetNamedGroupingPolicy("g")
//獲取策略中的所有角色繼承規則
namedGroupingPolicy := e.GetFilteredNamedGroupingPolicy("g", 0, "alice")
// 確定是否存在授權規則
hasPolicy := e.HasPolicy("data2_admin", "data2", "read")
//確定是否存在命名授權規則
hasNamedPolicy := e.HasNamedPolicy("p", "data2_admin", "data2", "read")
//向當前策略添加授權規則。 如果規則已經存在,函數返回false,並且不會添加規則。 否則,函數通過添加新規則並返回true
added := e.AddPolicy("eve", "data3", "read")
// 向當前命名策略添加授權規則。 如果規則已經存在,函數返回false,並且不會添加規則。 否則,函數通過添加新規則並返回true
added := e.AddNamedPolicy("p", "eve", "data3", "read")
// 從當前策略中刪除授權規則
removed := e.RemovePolicy("alice", "data1", "read")
// 移除當前策略中的授權規則,可以指定字段篩選器。 RemovePolicy 從當前策略中刪除授權規則
removed := e.RemoveFilteredPolicy(0, "alice", "data1", "read")
//從當前命名策略中刪除授權規則
removed := e.RemoveNamedPolicy("p", "alice", "data1", "read")
//從當前命名策略中移除授權規則,可以指定字段篩選器
removed := e.RemoveFilteredNamedPolicy("p", 0, "alice", "data1", "read")
//確定是否存在角色繼承規則
has := e.HasGroupingPolicy("alice", "data2_admin")
//確定是否存在命名角色繼承規則
has := e.HasNamedGroupingPolicy("g", "alice", "data2_admin")
// 向當前策略添加角色繼承規則。 如果規則已經存在,函數返回false,並且不會添加規則。 如果規則已經存在,函數返回false,並且不會添加規則
added := e.AddGroupingPolicy("group1", "data2_admin")
//將命名角色繼承規則添加到當前策略。 如果規則已經存在,函數返回false,並且不會添加規則。 否則,函數通過添加新規則並返回true
added := e.AddNamedGroupingPolicy("g", "group1", "data2_admin")
// 從當前策略中刪除角色繼承規則
removed := e.RemoveGroupingPolicy("alice", "data2_admin")
//從當前策略中移除角色繼承規則,可以指定字段篩選器
removed := e.RemoveFilteredGroupingPolicy(0, "alice")
//從當前命名策略中移除角色繼承規則
removed := e.RemoveNamedGroupingPolicy("g", "alice")
//當前命名策略中移除角色繼承規則,可以指定字段篩選器
removed := e.RemoveFilteredNamedGroupingPolicy("g", 0, "alice")
//添加自定義函數
func CustomFunction(key1 string, key2 string) bool {
if key1 == "/alice_data2/myid/using/res_id" && key2 == "/alice_data/:resource" {
return true
} else if key1 == "/alice_data2/myid/using/res_id" && key2 == "/alice_data2/:id/using/:resId" {
return true
} else {
return false
}
}
func CustomFunctionWrapper(args ...interface{}) (interface{}, error) {
key1 := args[0].(string)
key2 := args[1].(string)
return bool(CustomFunction(key1, key2)), nil
}
e.AddFunction("keyMatchCustom", CustomFunctionWrapper)
casbin的使用者
casbin-go語言使用者
名稱 | 描述 | 模型 | 策略 |
---|---|---|---|
VMware Harbor | VMware的開源可信雲本地註冊表項目,用於存儲、簽名和掃描內容。 | Code | Code |
Intel RMD | 英特爾的資源管理守護進程。 | .conf | .csv |
VMware Dispatch | 用於部署和管理無服務器風格應用程序的框架。 | Code | Code |
Skydive | 一個開源的實時網絡拓撲和協議分析器。 | Code | .csv |
Zenpress | 用Golang編寫的CMS系統。 | .conf | Gorm |
Argo CD | 爲Kubernetes持續提供的GitOps。 | .conf | .csv |
Muxi Cloud | 一種更容易管理Kubernetes集羣的方法。 | .conf | Code |
EngineerCMS | CMS管理工程師的知識。 | .conf | SQLite |
Cyber Auth API | 一個Golang身份驗證API項目 | .conf | .csv |
IRIS Community | IRIS社區活動網頁 | .conf | .csv |
Metadata DB | BB歸檔元數據數據庫。 | .conf | .csv |
Qilin API | 遊戲內容下的ProtocolONE許可證管理工具。 | Code | .csv |
3.權限系統設計模型分析
常見的設計模式(DAC,MAC,RBAC,ABAC)
自主訪問控制(DAC: Discretionary Access Control)
系統會識別用戶,然後根據被操作對象(Subject)的權限控制列表(ACL: Access Control List)或者權限控制矩陣(ACL: Access Control Matrix)的信息來決定用戶的是否能對其進行哪些操作,例如讀取或修改。
而擁有對象權限的用戶,又可以將該對象的權限分配給其他用戶,所以稱之爲“自主(Discretionary)”控制。
這種設計最常見的應用就是文件系統的權限設計,如微軟的NTFS。
DAC最大缺陷就是對權限控制比較分散,不便於管理,比如無法簡單地將一組文件設置統一的權限開放給指定的一羣用戶
強制訪問控制(MAC: Mandatory Access Control)
MAC是爲了彌補DAC權限控制過於分散的問題而誕生的。在MAC的設計中,每一個對象都都有一些權限標識,每個用戶同樣也會有一些權限標識,而用戶能否對該對象進行操作取決於雙方的權限標識的關係,這個限制判斷通常是由系統硬性限制的。比如在影視作品中我們經常能看到特工在查詢機密文件時,屏幕提示需要“無法訪問,需要一級安全許可”,這個例子中,文件上就有“一級安全許可”的權限標識,而用戶並不具有。
MAC非常適合機密機構或者其他等級觀念強烈的行業,但對於類似商業服務系統,則因爲不夠靈活而不能適用。
基於角色的訪問控制(RBAC: Role-Based Access Control)
因爲DAC和MAC的諸多限制,於是誕生了RBAC,並且成爲了迄今爲止最爲普及的權限設計模型。
RBAC在用戶和權限之間引入了“角色(Role)”的概念(暫時忽略Session這個概念):
如圖所示,每個用戶關聯一個或多個角色,每個角色關聯一個或多個權限,從而可以實現了非常靈活的權限管理。角色可以根據實際業務需求靈活創建,這樣就省去了每新增一個用戶就要關聯一遍所有權限的麻煩。簡單來說RBAC就是:用戶關聯角色,角色關聯權限。另外,RBAC是可以模擬出DAC和MAC的效果的。
基於屬性的權限驗證(ABAC: Attribute-Based Access Control)
ABAC被一些人稱爲是權限系統設計的未來。
不同於常見的將用戶通過某種方式關聯到權限的方式,ABAC則是通過動態計算一個或一組屬性來是否滿足某種條件來進行授權判斷(可以編寫簡單的邏輯)。屬性通常來說分爲四類:用戶屬性(如用戶年齡),環境屬性(如當前時間),操作屬性(如讀取)和對象屬性(如一篇文章,又稱資源屬性),所以理論上能夠實現非常靈活的權限控制,幾乎能滿足所有類型的需求。
例如規則:“允許所有班主任在上課時間自由進出校門”這條規則,其中,“班主任”是用戶的角色屬性,“上課時間”是環境屬性,“進出”是操作屬性,而“校門”就是對象屬性了。爲了實現便捷的規則設置和規則判斷執行,ABAC通常有配置文件(XML、YAML等)或DSL配合規則解析引擎使用。
用戶在攜帶自身的屬性值包括主題屬性,資源屬性,環境屬性,然後向資源發送請求,授權引擎 會根據subject所攜帶的屬性進行判斷,然後會給出拒絕或者同意的結果給用戶,然後就可以訪問資源。
總結一下,ABAC有如下特點:
- 集中化管理
- 可以按需實現不同顆粒度的權限控制
- 不需要預定義判斷邏輯,減輕了權限系統的維護成本,特別是在需求經常變化的系統中
- 定義權限時,不能直觀看出用戶和對象間的關係
- 規則如果稍微複雜一點,或者設計混亂,會給管理者維護和追查帶來麻煩
- 權限判斷需要實時執行,規則過多會導致性能問題
既然ABAC這麼好,那最流行的爲什麼還是RBAC呢?
大部分系統對權限控制並沒有過多的需求,而且ABAC的管理相對來說太複雜了。
ABAC有時也被稱爲PBAC(Policy-Based Access Control)或CBAC(Claims-Based Access Control)
4.百度超級鏈權限系統
wiki地址:https://github.com/xuperchain/xuperunion/wiki/2.-關鍵概念#26-賬戶權限控制模型
名詞解釋
-
AK(Access Key)
:具體的一個address,由密碼學算法生成一組公私鑰對,然後將公鑰用指定編碼方式壓縮爲一個地址。 -
賬號(Account)
: 在超級鏈上部署合約需要有賬號, 賬號可以綁定一組AK(公鑰),並且AK可以有不同的權重。 賬戶的名字具有唯一性。
模型介紹
系統會首先識別用戶,然後根據被操作對象的ACL的信息來決定用戶能否對其進行哪些操作
ACL(Access Control List)是最早也是最基本的一種訪問控制機制,它的原理非常簡單:每一項資源,都配有一個列表,這個列表記錄的就是哪些用戶可以對這項資源執行CRUD中的那些操作。當系統試圖訪問這項資源時,會首先檢查這個列表中是否有關於當前用戶的訪問權限,從而確定當前用戶可否執行相應的操作。總得來說,ACL是一種面向資源的訪問控制模型,它的機制是圍繞“資源”展開的
在超級鏈中,賬戶和合約的關係如下所述:
- 個人賬戶AK:是指一個具體的地址Addr;
- 用戶的創建是離線的行爲,可以通過命令行工具或者API進行創建
- 合約賬戶:超級鏈智能合約的管理單元。
- 賬戶的創建:
- 任何賬戶或者AK都可以調用系統級智能合約創建賬戶;
- 創建賬戶需要指定賬戶對應的擁有者的地址集,如果一個賬戶中只有一個地址, 那麼這個Addr對賬戶完全控制;
- 創建賬戶需要指定ACL控制策略,用於賬戶其他管理動作的權限控制;
- 創建賬戶需要消耗賬戶資源;
- 賬戶名命名規則;
- 中間爲長度爲16位字符串;
- 以"XC"開頭;
- 以"@鏈名"結尾;
- 賬戶管理:依地址集合據創建時指定的地址集和權限策略,管理賬戶其他操作;
- 賬戶股東剔除和加入;
- 賬戶資產轉賬;
- 創建合約,創建智能合約需要消耗賬戶資源,先將utxo資源打到賬戶下,通過消耗賬戶的utxo資源創建合約,驗證的邏輯需要走賬戶的ACL控制;
- 合約Method權限模型管理;
- 賬戶的創建:
- 智能合約:超級鏈中的一個具體的合約,屬於某個賬戶;
- 賬戶所屬人員允許在賬戶內部署合約;
- 賬戶所屬人員可以定義合約管理的權限模型;
- 設置合約方法的權限模型,合約內有一個權限表,記錄:{ contract.method,permission_model}
- 合約命名規則:長度爲4~16個字符(包括4和16),首字母可選項爲[ a-ZA-Z_ ],末尾字符可選項爲[ a-zA-Z0-9_ ],中間部分的字符可選項爲[ a-zA-Z_. ]
account := "XC0000000000000001@xuper" ak := "XC0000000000000001@xuper/dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN"
系統功能和設計
主要有兩個功能:賬號權限管理、合約權限管理
- 賬號權限管理 賬號的創建、添加和刪除AK、設置AK權重、權限模型
- 合約權限管理 設置合約調用權限, 支持2種權限模型: a. 背書閾值:在名單中的AK或Account簽名且他們的權重值加起來超過一定閾值,就可以調用合約 b. AK集合: 定義多組AK集合,集合內的AK需要全部簽名,集合間只要有一個集合有全部簽名即可
系統設計
權限策略:
var PermissionRule_name = map[int32]string{
0: "NULL", // 無權限控制
1: "SIGN_THRESHOLD",// 簽名閾值策略
2: "SIGN_AKSET", // AKSet簽名策略
3: "SIGN_RATE", // 簽名率策略
4: "SIGN_SUM", // 簽名個數策略
5: "CA_SERVER", // CA服務器鑑權
6: "COMMUNITY_VOTE",// 社區治理
}
//簽名閾值策略:
Sum{Weight(AK_i) , if sign_ok(AK_i)} >= acceptValue
權限測試例:
func Test_IdentifyAccount(t *testing.T) {
account := "XC0000000000000001@xuper"
ak := "XC0000000000000001@xuper/dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN"
pubkey := "{\"Curvname\":\"P-256\",\"X\":74695617477160058757747208220371236837474210247114418775262229497812962582435,\"Y\":51348715319124770392993866417088542497927816017012182211244120852620959209571}"
prikey := "{\"Curvname\":\"P-256\",\"X\":74695617477160058757747208220371236837474210247114418775262229497812962582435,\"Y\":51348715319124770392993866417088542497927816017012182211244120852620959209571,\"D\":29079635126530934056640915735344231956621504557963207107451663058887647996601}"
msg := "this is the test message from permission"
xcc, err := crypto_client.CreateCryptoClientFromJSONPublicKey([]byte(pubkey))
if err != nil {
t.Error("create crypto client failed, err=", err)
return
}
ecdsaPriKey, err := xcc.GetEcdsaPrivateKeyFromJSON([]byte(prikey))
if err != nil {
t.Error("get private key failed, err=", err)
return
}
sign, err := xcc.SignECDSA(ecdsaPriKey, []byte(msg))
if err != nil {
t.Error("sign failed, err=", err)
return
}
signInfo := &pb.SignatureInfo{
Sign: sign,
PublicKey: pubkey,
}
aks := make([]string, 1)
signs := make([]*pb.SignatureInfo, 1)
aks[0] = ak
signs[0] = signInfo
aclMgr, err := acl_mock.NewFakeACLManager()
if err != nil {
t.Error("NewAclManager failed, err=", err)
return
}
pm := &pb.PermissionModel{
Rule: pb.PermissionRule_SIGN_THRESHOLD,
AcceptValue: 1,
}
aclObj := &pb.Acl{
Pm: pm,
AksWeight: make(map[string]float64),
}
aclObj.AksWeight["dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN"] = 1
aclMgr.SetAccountACL(account, aclObj)
//主要爲了實現IdentifyAccount方法
//SetAccountAC/ IdentifyAccount檢查aks和符號是否匹配,這些aks可以通過account的ACL策略表示 給定的帳戶。如果簽名匹配aks,並且aks可以代表帳戶,則返回true。將賬戶acl保存在內存中
result, err := IdentifyAccount(account, aks, signs, []byte(msg), aclMgr)
if err != nil || !result {
t.Error("IdentifyAccount failed, err=", err)
return
}
fakesign := "this is a fake signature"
signInfo2 := &pb.SignatureInfo{
Sign: []byte(fakesign),
PublicKey: pubkey,
}
signs[0] = signInfo2
result, err = IdentifyAccount(account, aks, signs, []byte(msg), aclMgr)
if result == true {
t.Error("IdentifyAccount fake sign failed, result=", result)
}
}
在IdentifyAccount方法中主要實現:
func IdentifyAccount(account string, aksuri []string, signs []*pb.SignatureInfo,
msg []byte, aclMgr acl.ManagerInterface) (bool, error) {
akslen := len(aksuri)
signslen := len(signs)
// aks and signs could have zero length for permission rule Null
if akslen != signslen || aclMgr == nil {
return false, fmt.Errorf("Invalid Param, akslen=%d,signslen=%d,aclMgr=%v", akslen, signslen, aclMgr)
}
// build perm tree
pnode, err := ptree.BuildAccountPermTree(aclMgr, account, aksuri, signs)
if err != nil {
return false, err
}
return validatePermTree(pnode, msg, true)
}
在這其中主要實現buildAccountPermTree和validatePermTree兩個方法,Pnode定義了perm 樹的節點
type PermNode struct { Name string // the name(id) of account/ak/method ACL *pb.Acl // the ACL definition of this account/method Status ValidateStatus // the ACL validation status of this node SignInfo *pb.SignatureInfo // the signature info of this node, only AK have this field Children []*PermNode // the children of this node, usually are ACL members of account/method } const ( _ ValidateStatus = iota // NotVerified : not verified by ACLValidator NotVerified // Success : ACLValidator verified successful Success // Failed : ACLValidator verified failed Failed )
它也沒有使用PERM模型,至於爲什麼會用Perm這個詞,目前也沒想明白。
5.ABAC 模型示例
package main
import (
"fmt"
"github.com/casbin/casbin"
"github.com/casbin/casbin/model"
)
const modelText = `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj,act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub.App == r.obj.App && r.sub.Type == r.obj.Type && r.sub.Method == r.obj.Method && r.sub.Name == r.obj.Name \
&& r.sub.Read == r.act.Read && r.sub.Write == r.act.Write
`
type User struct {
Id int
UserName string
Group []Group
}
type Group struct {
Id int
Name string
Read bool
Write bool
App string // app
Type string // 類型
Method string // 方法
Priority int // 優先級
}
type Obj struct {
App string // app
Name string
Type string // 類型
Method string // 方法
}
type Act struct {
Read bool
Write bool
}
func main() {
m := model.Model{}
m.LoadModelFromText(modelText)
e:= casbin.NewEnforcer(m)
group1 := Group{
Name: "lk",
Read: true,
Write: true,
App: "asset",
Type: "user",
Method: "Get",
Priority: 100,
}
//group2 中Name和Write 不與Obj資源和執行操作權限中相同
group2 := Group{
Name: "lkTest",
Read: true,
Write: false,
App: "asset",
Type: "user",
Method: "Get",
Priority: 100,
}
// 用戶 palletone 屬於 group1 , group2
user1 := User{
UserName: "palletone",
Group: []Group{group1, group2},
}
//資源屬性
obj := Obj{
App: "asset",
Name: "lk",
Type: "user",
Method: "Get",
}
//當執行操作權限 Read Write爲True時 策略執行結果爲allow
act := Act{
Read:true,
Write:true,
}
// 檢查 用戶 palletone 所有的組 是否有權限
for _, v := range user1.Group {
//強制決定一個“subject”是否可以通過操作“action”訪問一個“object”,輸入參數通常是:(sub, obj, act)。
flag:= e.Enforce(v, obj, act)
if flag {
fmt.Println("權限正常")
} else {
fmt.Println("沒有權限")
}
}
}
//打印結果
//權限正常
//沒有權限