• Casbin + Gin + Gorm 学习探索


    Casbin 是一个强大的,开源的访问控制框架,权限管理机制支持多种访问控制模型; 并且支持多种编程语言; 

     文档地址:https://casbin.org/docs/zh-CN/overview

    Gin Golang 的 Web 框架,短小精悍

     文档地址: https://gin-gonic.com/docs/

    Gorm Golang 的 ORM 框架

     文档地址:http://gorm.book.jasperxu.com/

    今天我们要学习的是如何通过Casbin 来控制开发的 API 访问权限 

    ##### Casbin 工作原理

      访问控制模型被抽象为PERM(Policy,Effect,Request,Matcher) 的一个文件,如果切换项目的授权机制只用修改文件即可; 

      Policy: 定义权限的规则 

      Effect: 定义组合多个Policy 后是允许还是拒绝(allow/deny)

      Request: 访问的请求,可以理解为谁想访问什么资源

      Matcher:判断Request 是否满足Policy ,返回true或false 

    ##### 在使用Casbin 控制后台接口时使用以下模型

    [request_definition]
        r = sub, obj, act
    # 请求的规则 
    # r 是规则的名称,sub 为请求的实体,obj 为资源的名称, act 为请求的实际操作动作 [policy_definition] p
    = sub, obj, act # 策略的规则
    # 同请求 [role_definition] g
    = _, _ # 角色的定义
    # g 角色的名称,第一个位置为用户,第二个位置为角色,第三个位置为域(在多租户场景下使用) [policy_effect] e
    = some(where (p.eft == allow)) # 任意一条 policy rule 满足, 则最终结果为 allow [matchers] m = g(r.sub, p.sub) == true && keyMatch2(r.obj, p.obj) == true && regexMatch(r.act, p.act) == true || r.sub == "root"
    # 前三个用来匹配上面定义的请求的规则, 最后一个或条件为:如果实体是root 直接通过, 不验证权限

    在理解了Casbin 的工作原理后,实际写代码测试一下

    需要使用的外部包

    go get github.com/casbin/casbin  Casbin 官方库

    go get github.com/casbin/gorm-adapter  Casbin 插件,用来将规则和策略保存到数据库中

    go get github.com/gin-gonic/gin  Go Web 框架

    go get github.com/go-sql-driver/mysql  Go MySQL 驱动 

    go get github.com/jinzhu/gorm  Go ORMpackage mainimport (    "fmt"    "github.com/casbin/casbin"

        "github.com/casbin/gorm-adapter"
        "github.com/gin-gonic/gin"
        _ "github.com/go-sql-driver/mysql"
        "github.com/jinzhu/gorm"
    )
    
    // 统一响应结构体 type Response
    struct { Code int `json:"code"` Message string `json:"message"` Data interface{} `json:"data"` } var O *gorm.DB var PO *gormadapter.Adapter var Enforcer *casbin.Enforcer
    func ping(c
    *gin.Context) { var response Response response.Code = 0 response.Message = "success" response.Data = "" c.JSON(200, response) return } // 数据库连接及角色规则的初始化 func connect() { dsn := "xxx:xxx@(xxxx:3xx6)/goapp?charset=utf8&parseTime=True&loc=Local" var err error O, err = gorm.Open("mysql", dsn) if err != nil { fmt.Println("connect DB error") panic(err) }
       // 将数据库连接同步给插件, 插件用来操作数据库 PO
    = gormadapter.NewAdapterByDB(O)
    // 这里也可以使用原生字符串方式
    // Enforcer
    = casbin.NewEnforcer("./auth_model.conf", PO)
    // 开启权限认证日志 Enforcer.EnableLog(
    true)
    // 加载数据库中的策略 err
    = Enforcer.LoadPolicy() if err != nil { fmt.Println("loadPolicy error") panic(err) } // 创建一个角色,并赋于权限
    // admin 这个角色可以访问GET 方式访问 /api/v2/ping res := Enforcer.AddPolicy("admin","/api/v2/ping","GET") if !res { fmt.Println("policy is exist") } else { fmt.Println("policy is not exist, adding") } // 将 test 用户加入一个角色中 Enforcer.AddRoleForUser("test","root")
    Enforcer.AddRoleForUser("tom","admin")
    // 请看规则中如果用户名为 root 则不受限制 } func main() { defer O.Close() connect() g := gin.Default()
      // 这里的接口没有使用权限认证中间件 version1 :
    = g.Group("/api/v1") { version1.GET("/ping", ping) // 这个是通用的接口 }
    // 接口使用权限认证中间件 version2 :
    = g.Group("/api/v2", CasbinMiddleWare) { version2.GET("/ping", ping) } _ = g.Run(":8099") } // casbin middleware 权限认证中间件 func CasbinMiddleWare(c *gin.Context) { var userName string userName = c.GetHeader("userName") if userName == "" { fmt.Println("headers invalid") c.JSON(200, gin.H{ "code": 401, "message": "Unauthorized", "data": "", }) c.Abort() return } // 请求的path p := c.Request.URL.Path // 请求的方法 m := c.Request.Method
    // 这里认证 res,err := Enforcer.EnforceSafe(userName,p,m) // 这个 HasPermissionForUser 跟上面的有什么区别
    // EnforceSafe 会验证角色的相关的权限
    // 而 HasPermissionForUser 只验证用户是否有权限
    //res = Enforcer.HasPermissionForUser(userName,p,m) if err != nil { fmt.Println("no permission ") fmt.Println(err) c.JSON(200, gin.H{ "code": 401, "message": "Unauthorized", "data": "", }) c.Abort() return } if !res { fmt.Println("permission check failed") c.JSON(200, gin.H{ "code": 401, "message": "Unauthorized", "data": "", }) c.Abort() return } c.Next() }

    程序运行后数据库数据为

     p 代表的是策略 admin 角色可以使用GET 访问 /api/v2/ping 

     g 代表的是角色 test 用户在root 角色中

                               tom 在admin 角色中

    所以在测试时请求头

    userName = root 有正常响应 (这里不会到数据库验证,策略最后一条)

    userName = tom 正常响应 (tom 有admin 角色 , 所以验证通过)

    userName = role_admin 正常响应 (参考这里:https://casbin.org/docs/zh-CN/rbac , 正常情况下用户名和角色名称不应该一样)

    userName = *** 都无法通过认证

    ########

       最后, 一般的后台开发不会这样设计, 后面继续学习,理解 Casbin 工作原理,为以后开发打下基础; 

  • 相关阅读:
    BizTalk开发系列(三十一)配置和使用HTTP适配器
    BizTalk开发系列(三) 单机环境下的BizTalk Server 2006 R2安装
    BizTalk开发系列(二) "Hello World" 程序搬运文件
    BizTalk开发系列(三十二)浅谈BizTalk主机性能优化
    BizTalk开发系列(二十四) BizTalk项目框架建议
    BizTalk开发系列(二十八) MSMQ 适配器
    BizTalk开发系列(三十五) TCP/IP 适配器
    BizTalk开发系列(十四) XML空白字符(WhiteSpace)
    BizTalk开发系列(一) "Hello World"
    使用Xpath对XML进行模糊查询
  • 原文地址:https://www.cnblogs.com/Mail-maomao/p/11951482.html
Copyright © 2020-2023  润新知