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:[email protected](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 工作原理,为以后开发打下基础;

原文地址:https://www.cnblogs.com/Mail-maomao/p/11951482.html

时间: 2024-10-16 16:40:01

Casbin + Gin + Gorm 学习探索的相关文章

Android学习探索之Java 8 在Android 开发中的应用

前言: Java 8推出已经将近2年多了,引入很多革命性变化,加入了函数式编程的特征,使基于行为的编程成为可能,同时减化了各种设计模式的实现方式,是Java有史以来最重要的更新.但是Android上,一直没有看到支持Java8的消息.Android到底会不会支持Java8呢?答案是肯定的,Android N已经开始支持Java 8 了. 关于Java 8 (1.)使用Lambda表达式 Java 8的一大亮点是引入Lambda表达式,使用它设计的代码会更加简洁.当开发者在编写Lambda表达式时

margin学习探索

对于页面布局,margin为css中非常常用的一个属性,和padding一样常用作元素位置控制的属性.padding以后会进行续写. 1.margin属性,用于设置边距,不会继承也不会遗传给子元素,写法有4种.   1.1. margin: 5px; 一个值的时候,表示上下左右四个边边距都为5像素   1.2. margin: 5px 1px; 2个值的时候,表示上下边距5像素,左右边距1像素   1.3. margin:5px 1px 5px; 3个值的时候,表示上边距5像素,左右1像素,下边

gin+gorm

在[环境变量]中添加如下[用户变量]/[系统变量]:GO111MODULE,值为on go mod init目录 在项目中新建文件main.go,并添加测试代码 package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message&quo

学习 探索

<整理的艺术2>实用技巧分享 别一次把资料全部整理完 这条对我无效,因为我有个非常好的习惯,在每天下班前10分钟,把当天的工作资料全部归纳.整理. 学会放松 书中有一条技巧是利用身边的度假村和温泉,那是日本的作法. 自己觉得累的时间,大都是脑力活动,这里比如的办法是多运动,比如慢跑.游泳之类,然后找个正规按摩店(在北方良子足道多一点)做脚道按摩或全身按摩,然后睡一觉,睡醒后经常满血复活. 每个人的选择不同,有人去爬山,有人去泡温泉.逛街,关键是要找到几种适合自己的放松方法,适当的放松,记住玩游

gin+vue的前后端分离开源项目

该项目是gin+vue的前后端分离项目,使用gorm访问MySQL,其中vue前端是使用vue-element-admin框架简单实现的: go后台使用jwt,对API接口进行权限控制.此外,Web页面在token过期后的半个小时内,用户再次操作会自动刷新token: 项目很小,适合gin新手学习!(后续有时间会补上相关教程) GitHub地址:https://github.com/Bingjian-Zhu/gin-vue 一.运行go后台项目 (1)把项目clone到GOPATH/src目录下

VS中Qt的探索02

边看C++ GUI QT4教程,边在VS2010中进行编程学习探索. 在使用Qt设计师时,其中每一个对象的ObjectName属性是非常重要的,在程序功能的实现过程中,需要不断的使用该变量名. 当所有的对象属性设置完之后,在VS2010中右击*.ui文件,选择编译(ctrl+F7),便会自动生成另一个.h文件,里面的某一个类包含了对象的所有属性情况,如下图所示: 并且在VS自动生成的*.h文件中,会有一个该类的变量名用来访问你在Qt设计师中更改的每个对象的属性值,从而我们可以在实现某项功能时进行

探索推荐引擎内部的秘密,第 1 部分: 推荐引擎初探

"探索推荐引擎内部的秘密"系列将带领读者从浅入深的学习探索推荐引擎的机制,实现方法,其中还涉及一些基本的优化方法,例如聚类和分类的应用.同时在理论讲解的基础上,还会结合 Apache Mahout 介绍如何在大规模数据上实现各种推荐策略,进行策略优化,构建高效的推荐引擎的方法.本文作为这个系列的第一篇文章,将深入介绍推荐引擎的工作原理,和其中涉及的各种推荐机制,以及它们各自的优缺点和适用场景,帮助用户清楚的了解和快速构建适合自己的推荐引擎. 信息发现 如今已经进入了一个数据爆炸的时代,

C#中使用Redis学习一 windows安装redis服务器端和客户端

学习背景 今天是2015年1月2日,新年刚开始的第二天,先祝大家元旦快乐啦(迟到的祝福吧^_^).前段时间一直写Jquery插件开发系列博文,这个系列文章暂停一段时间,最近一直在看redis,我将把redis作为一个系列写一下我的学习历程.正好现在项目中使用了redis,本着学习探索的精神,准备写一下我对redis的一个学习历程和自己的一点感悟.在学习过程中也走了很多弯路,希望能对看这篇博文的朋友们带来点帮助.也算是写这边博文的最大目的了. 我在认识redis之前没有接触过任何NoSql思想.对

邹欣老师的《构建之法》第一章“概论”学习笔记与自我随笔

刚读完了邹欣老师的<构建之法>第一章“概论”,四个字形容:酣畅淋漓. 概论将自己的一些模糊的认识清晰化,用准确的文字描述了出来,填补了脑海里的一些灰色地带. 总结一下:概论通俗地阐述了编程.软件.计算机科学.软件工程的联系与区别,简单说,编程是一项具体动作,软件是供人使用的产品,具体有很多种类型,而计算机科学是偏向理论研究,软件工程就像其他工程学一样,是在一定条件下合理配置资源达到生产软件的目的. 本人作为一名从小对编程.软件.计算机感兴趣的Nerd,虽然大学专业与此无关,但刚毕业时签了一份软