本文以
iris
框架做爲示例,原生或其它框架基本是同樣的。
根據官方文檔,首先介紹一下幾個重要部位。(安裝方法跳過)git
使用casbin
有兩個地方是須要配置的,一個是model
,另外一個是policy
github
咱們作權限控制用得比較多的是RBAC
(基於角色的權限控制)golang
看過官方文檔的同窗都知道,model的內容來源能夠是.conf
文件,也能夠是在代碼中編寫;可是policy內容應該是動態的,能夠隨時更新的,把它放.csv
文件裏管理起來多不方便?稍安勿躁,後面會說說個人解決方法。app
package main import ( "github.com/kataras/iris" "github.com/casbin/casbin" cm "github.com/iris-contrib/middleware/casbin" ) var Enforcer = casbin.NewEnforcer("casbin_model.conf", "casbi_npolicy.csv") func newApp() *iris.Application { casbinMiddleware := cm.New(Enforcer) app := iris.New() app.WrapRouter(casbinMiddleware.Wrapper()) app.Get("/", hi) app.Any("/dataset1/{p:path}", hi) app.Post("/dataset1/resource1", hi) app.Get("/dataset2/resource2", hi) app.Post("/dataset2/folder1/{p:path}", hi) app.Any("/dataset2/resource1", hi) return app } func main() { app := newApp() app.Run(iris.Addr(":8080")) } func hi(ctx iris.Context) { ctx.Writef("Hello %s", cm.Username(ctx.Request())) }
上面是iris文檔上的一段示例代碼,可能版本不同了,我運行下面的代碼會直接報錯,緣由是github.com/iris-contrib/middleware/casbin/casbin.go
裏面的一個方法:框架
func (c *Casbin) Check(r *http.Request) bool { username := Username(r) method := r.Method path := r.URL.Path b:=c.enforcer.Enforce(username, path, method)//這裏c.enforcer.Enforce返回兩個值,一個是bool,另外一個是error,這裏只定義了一個,因此報錯了 return b }
還有一個問題是,這個中間件默認採用BasicAuth獲取用戶名的,若是你也是採用這種方法,那就大吉大利了,若是不是,仍是本身動手取用戶名吧ide
既然是一個簡單的測試,那就簡單粗暴的直接改寫整個casbin.go
文件測試
//RBAC1 //請求定義 //sub 想要訪問資源的用戶 //obj 要訪問的資源 //act 用戶對資源執行的操做,act能夠是read、write、print等等你想要自定義的操做 [request_definition] r = sub, obj, act //策略定義,也就是*.cvs文件 p 定義的格式 [policy_definition] p = sub, obj, act //組定義,也就是*.cvs文件 g 定義的格式。g是用戶組或角色 [role_definition] g = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")
p,abc123,/user,GET //用戶abc123對/user有GET權限,下面同理 p,abc123,/user,POST p,admin,/test,* //角色或用戶組admin對/test有全部權限 g,super_admin,admin //用戶super_admin屬於admin組或角色
複製整個casbin.go
文件到本身的項目下,我把它放在/middleware/
裏面了code
/middleware/casbin.go router
package middleware import ( "github.com/casbin/casbin" "github.com/kataras/iris/context" "net/http" ) func New(e *casbin.Enforcer) *Casbin { return &Casbin{enforcer: e} } func (c *Casbin) Wrapper() func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) { return func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) { if !c.Check(r) { w.WriteHeader(http.StatusForbidden) _, _ = w.Write([]byte("403 Forbidden")) return } router(w, r) } } func (c *Casbin) ServeHTTP(ctx context.Context) { if !c.Check(ctx.Request()) { ctx.StatusCode(http.StatusForbidden) // Status Forbiden ctx.StopExecution() return } ctx.Next() } type Casbin struct { enforcer *casbin.Enforcer } func (c *Casbin) Check(r *http.Request) bool { username := Username(r) method := r.Method path := r.URL.Path b,_:=c.enforcer.Enforce(username, path, method) return b } func Username(r *http.Request) string { //username, _, _ := r.BasicAuth()//這玩意我用不上,把它註釋掉 return "abc123" //直接返回用戶名,看看測試效果 }
main.go 中間件
package main import ( "github.com/kataras/iris" "github.com/casbin/casbin" cm "project_path/middleware/casbin" ) var e = casbin.NewEnforcer("casbin_model.conf", "casbi_npolicy.csv") func newApp() *iris.Application { casbinMiddleware := cm.New(e) app := iris.New() app.WrapRouter(casbinMiddleware.Wrapper()) // 若是不想使用中間件,能夠經過下面方法進行判斷 /* if b,err:=e.Enforce("abc123","/user","Get");b { fmt.Println("成功") } else { fmt.Println("失敗") } */ app.Get("/user", hi) app.Post("/user", hi) app.Put("/test", hi) return app } func main() { app := newApp() app.Run(iris.Addr(":8080")) } func hi(ctx iris.Context) { ctx.Writef("當你看到這個,說明經過了權限驗證") }
好 ,就這麼簡單,下面使用
Get訪問localhost:8080/user
Post訪問localhost:8080/user
上面兩個訪問都成功經過驗證了,下面的
Get、Post、Put、Delete等等訪問localhost:8080/test
都返回了403 Forbidden,當把Username
方法改成return "super_admin"
再訪問試試。
現實項目中,可能會把Check
方法中的username
改成用戶ID或者郵箱或者手機號都是能夠的。
policy 待續...