<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [官方文檔](https://casbin.org/docs/zh-CN/overview) thinkphp6:[think-casbin](https://github.com/php-casbin/think-casbin) [文檔](http://www.hmoore.net/oldlei/casbin/1289453) ## 什么是驗證授權 > 授權(英語:Authorization)一般是指對信息安全或計算機安全相關的資源定義與授予訪問權限,尤指訪問控制。動詞“授權”可指定義訪問策略與接受訪問。 `授權`作為名詞,其代表的是在計算機系統中定義的資源訪問權限。而`驗證授權`就是驗證計算機帳戶是否有資源的訪問權限。 舉個栗子,假設現在有一本書`book1`,其擁有`read`, `write`的操作,那么我們可以先定義以下`授權`: 1. `alice`可以`read`書籍`book1` 2. `bob`可以`write`書籍`book1` 3. `bob`可以`read`書籍`book1` 現在來了一個用戶`alice`她想`write`書籍`book1`,這時調用驗證授權功能模塊的接口,驗證授權功能模塊根據上述`授權`規則可以快速判斷`alice`不可以`write`書籍`book1`;過一會兒又來了一個用戶`bob`他想`write`書籍`book1`,這時調用驗證授權系統的接口,驗證授權系統根據上述`授權`規則可以快速判斷`bob`可以`write`書籍`book1`。 可以看到`身份認證系統`強調地是安全可靠地得到計算機用戶的身份信息,而`驗證授權`強調地是根據計算機的身份信息、訪問的資源、對資源的操作等給出一個Yes/No的答復。 ## 常用授權模型 ### ACL ### RBAC ### ABAC ## 實現權限驗證 前面提到了多種不同的權限模型,要完全自研實現不同的權限模型還是挺麻煩的。幸好`casbin`出現,它將上述不同的模型抽象為自己的`PERM metamodel`,這個`PERM metamodel`只包括`Policy`, `Effect`, `Request`, `Matchers`,只通過這幾個模型對象的組合即可實現上述提到的多種權限模型,如果業務上需要切換權限模型,也只需要配置一下`PERM metamodel`,并不需要大改權限模型相關的代碼,這一點真的很贊!!! 一個最簡單的`ACL`權限模型即可像下面這樣定義: `acl_simple_model.conf` ~~~javascript # 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_simple_policy.csv` ~~~javascript p, alice, data1, read p, bob, data2, write ~~~ 這意味著`alice`可以`read`資源`data1`;`bob`可以`write`資源`data2`。 寫一個簡單的程序就可以完成該權限驗證: ~~~javascript package main import ( "fmt" "github.com/casbin/casbin/v2" ) func main() { e, _ := casbin.NewSyncedEnforcer("acl_simple_model.conf", "acl_simple_policy.csv") sub := "alice" // the user that wants to access a resource. obj := "data1" // the resource that is going to be accessed. act := "read" // the operation that the user performs on the resource. if passed, _ := e.Enforce(sub, obj, act); passed { // permit alice to read data1 fmt.Println("Enforce policy passed.") } else { // deny the request, show an error fmt.Println("Enforce policy denied.") } } ~~~ ## casbin模型詳解 `casbin`官方其實已經提供了多種模型的定義及示例policy定義,見這里。而且為了便于用戶理解診斷模型及policy,還給了個在線的editor,修改模型或policy時可以利用此工具。 從上面的示例可以看出基于`casbin`實現權限驗證,代碼很簡單,但`casbin`的模型定義及policy定義初看還是挺復雜的,這樣詳細理解一下。 `casbin`的模型定義里會出現4個部分:`[request_definition]`,`[policy_definition]`,`[policy_effect]`, `[matchers]`。 其中`[request_definition]`描述的是訪問請求的定義,如下面的定義將訪問請求的三個參數分別映射為`r.sub`、`r.obj`、`r.act`(注意并不是所有的訪問請求一定是3個參數): ~~~javascript [request_definition] r = sub, obj, act ~~~ 同理`[policy_definition]`描述的是授權policy的定義,如下面的定義將每條授權policy分別映射為`p.sub`、`p.obj`、`p.act`(注意并不是所有的授權policy一定是3個參數,也不是必須只有一條授權policy定義): ~~~javascript [policy_definition] p = sub, obj, act ~~~ `[matchers]`描述的是根據訪問請求如何找到匹配的授權policy,如下面的定義將根據`r.sub`、`r.obj`、`r.act`、`p.sub`、`p.obj`、`p.act`找到完全匹配的授權policy: ~~~javascript [matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.act ~~~ 在寫`[matchers]`規則是還可以使用一些內置或自定義函數,參考[這里的文檔](https://casbin.org/docs/en/syntax-for-models#functions-in-matchers)。 最后`[policy_effect]`描述如果找到匹配的多條的授權policy,最終給出的驗證授權結果,如下面的定義說明只要有一條匹配的授權策略其`eft`是`allow`,則最終給出的驗證授權結果就是`允許`(注意每條授權policy默認的eft就是allow)。 ~~~javascript [policy_effect] e = some(where (p.eft == allow)) ~~~ 如果使用`RBAC`權限模型,可能還會使用`[role_definition]`,這個`[role_definition]`算是最復雜的了,其可以描述user-role之間的映射關系或resource-role之間的映射關系。這么說比較抽象,還是舉例說明: 假設模型定義如下: ~~~javascript [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 ~~~ 授權policy文件如下: ~~~javascript p, data2_admin, data2, read p, data2_admin, data2, write g, alice, data2_admin ~~~ 現在收到了授權請求`alice, data2, read`,這時`r.sub`為`alice`,根據`g = _, _`及`g(r.sub, p.sub)`,我們可以得出對應的`p.sub`可以為`data2_admin`,接下來再根據`r.obj == p.obj && r.act == p.act`,最終找到匹配的授權policy規則為`p, data2_admin, data2, read`,最后根據`some(where (p.eft == allow))`規則,此時驗證授權的結果就應該是`allow`。 這里`casbin`根據`r.sub`查找對應`p.sub`的過程還會考慮角色繼承。考慮以下授權policy文件: ~~~javascript p, reader, data2, read p, writer, data2, write g, admin, reader g, admin, writer g, alice, admin ~~~ 現在收到了授權請求`alice, data2, read`,這時`r.sub`為`alice`,根據`g = _, _`及`g(r.sub, p.sub)`,我們可以得出對應的`p.sub`可以為`admin`,`reader`,`writer`,接下來再根據`r.obj == p.obj && r.act == p.act`,最終找到匹配的授權policy規則為`p, reader, data2, read`,最后根據`some(where (p.eft == allow))`規則,此時驗證授權的結果就應該是`allow`。 通過`[role_definition]`還可以定義resource-role之間的映射關系,見[示例](https://github.com/casbin/casbin/blob/master/examples/rbac_with_resource_roles_model.conf)。 `casbin`的模型大概就是上面描述的了,很多概念理解起來可能比較費勁,結合示例及在[editor](https://casbin.org/en/editor)上做些實驗應該理解得更快一些。 ## casbin相關事項 1. `casbin`的模型定義及授權policy定義還可以選擇保存在其它存儲中,見[Model Storage](https://casbin.org/docs/en/model-storage)、[Policy Storage](https://casbin.org/docs/en/policy-storage)、[Adapters](https://casbin.org/docs/en/adapters)。 2. `casbin`的`Enforcer`對象還提供了一系列API接口管理授權policy規則,見[Management API](https://casbin.org/docs/en/management-api)、[RBAC API](https://casbin.org/docs/en/rbac-api)。 3. 可以修改授權policy規則,那么當多個驗證授權服務分布式部署時,必然要考慮某個服務修改了授權規則后,其它服務示例必須進行規則的同步。`casbin`也考慮到了這個需求,提供了Watchers機制,用于在觀察到授權規則發生變更時進行必要的回調,見[Watchers](https://casbin.org/docs/en/watchers)。 4. 在多線程環境下使用`Enforcer`對象的接口,必須使用`casbin.NewSyncedEnforcer`創建`Enforcer`,另外還支持授權policy`AutoLoad`特性,見[這里](https://casbin.org/docs/en/multi-threading)。 5. `casbin`默認是從授權policy文件中加載角色及角色的繼承信息的,也可以從其它外部數據源獲取這些信息,見[這里](https://casbin.org/docs/en/role-managers)。 ## casbin代碼分析 `casbin`整體代碼很簡單,很多代碼都是模型定義及授權policy定義加載的邏輯,關鍵代碼只有一個方法[Enforce](https://github.com/casbin/casbin/blob/master/enforcer.go#L329),見下面: ~~~javascript if !e.enabled { return true, nil } functions := make(map[string]govaluate.ExpressionFunction) for key, function := range e.fm { functions[key] = function } if _, ok := e.model["g"]; ok { for key, ast := range e.model["g"] { rm := ast.RM functions[key] = util.GenerateGFunction(rm) } } expString := e.model["m"]["m"].Value expression, err := govaluate.NewEvaluableExpressionWithFunctions(expString, functions) if err != nil { return false, err } rTokens := make(map[string]int, len(e.model["r"]["r"].Tokens)) for i, token := range e.model["r"]["r"].Tokens { rTokens[token] = i } pTokens := make(map[string]int, len(e.model["p"]["p"].Tokens)) for i, token := range e.model["p"]["p"].Tokens { pTokens[token] = i } parameters := enforceParameters{ rTokens: rTokens, rVals: rvals, pTokens: pTokens, } if policyLen := len(e.model["p"]["p"].Policy); policyLen != 0 { policyEffects = make([]effect.Effect, policyLen) matcherResults = make([]float64, policyLen) if len(e.model["r"]["r"].Tokens) != len(rvals) { return false, errors.New( fmt.Sprintf( "invalid request size: expected %d, got %d, rvals: %v", len(e.model["r"]["r"].Tokens), len(rvals), rvals)) } for i, pvals := range e.model["p"]["p"].Policy { // log.LogPrint("Policy Rule: ", pvals) if len(e.model["p"]["p"].Tokens) != len(pvals) { return false, errors.New( fmt.Sprintf( "invalid policy size: expected %d, got %d, pvals: %v", len(e.model["p"]["p"].Tokens), len(pvals), pvals)) } parameters.pVals = pvals result, err := expression.Eval(parameters) // log.LogPrint("Result: ", result) if err != nil { return false, err } switch result := result.(type) { case bool: if !result { policyEffects[i] = effect.Indeterminate continue } case float64: if result == 0 { policyEffects[i] = effect.Indeterminate continue } else { matcherResults[i] = result } default: return false, errors.New("matcher result should be bool, int or float") } if j, ok := parameters.pTokens["p_eft"]; ok { eft := parameters.pVals[j] if eft == "allow" { policyEffects[i] = effect.Allow } else if eft == "deny" { policyEffects[i] = effect.Deny } else { policyEffects[i] = effect.Indeterminate } } else { policyEffects[i] = effect.Allow } if e.model["e"]["e"].Value == "priority(p_eft) || deny" { break } } } ~~~ 這個代碼邏輯很清楚了,就是根據`[matchers]`、`[request_definition]`、`[policy_definition]`找到匹配的`[policy_definition]`,再根據`[policy_effect]`最后得出最終的驗證授權結果。可以看到該處理邏輯里大量地遍歷了`e.model["r"]["r"].Tokens`、`e.model["p"]["p"].Tokens`、`e.model["p"]["p"].Policy`,當授權policy規則條數較多時,估計性能不會太好。但官方給了個[性能測試報告](https://casbin.org/docs/en/benchmark),據說性能還可以,這個后面還須再驗證下。 為了優化性能,其實是可以將驗證授權操作的結果進行緩存,官方也提供了[CachedEnforcer](https://github.com/casbin/casbin/blob/master/enforcer_cached.go),目測邏輯沒問題,如果確實遇到性能瓶頸,可以考慮采用。 ## 其它外部支援 一些開源愛好者為`casbin`貢獻了[很多中間件組件](https://casbin.org/docs/en/middlewares),便于在多個編程語言中集成`casbin`進行權限驗證。 還有一些開源愛好者為`casbin`貢獻了[模型管理及授權策略管理的web前端](https://casbin.org/docs/en/admin-portal),如果覺得手工修改授權策略文件不直觀的話,可以考慮采用。 還可以看到目前[很多開源項目](https://casbin.org/docs/en/adopters)的權限驗證部分都是采用了`casbin`來實現的,例如[harbor里的rbac權限驗證](https://github.com/goharbor/harbor/tree/master/src/common/rbac)。 還發現一個基于`casbin`實現的身份認證及驗證授權服務,[這個例子](https://github.com/Soontao/go-simple-api-gateway)以后可以好好參考一下。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看