casbin访问控制框架在GO中的基本使用方法

我对casbin的理解

本文以 iris框架做为示例,原生或其它框架基本是同样的。

根据官方文档,首先介绍一下几个重要部位。(安装方法跳过)git

使用casbin有两个地方是须要配置的,一个是model,另外一个是policygithub

咱们作权限控制用得比较多的是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文件测试

开始动手

/rbac_model.conf

//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 == "*")

/rbac_policy.csv (注释删掉)

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 待续...

相关文章
相关标签/搜索