casbin + gin + gorm
实际项目中肯定要用rbac这种权限模型,并且需要进行url匹配验证,因此model使用如下
rbac_model.conf
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
# 当访问实体为root时直接认证通过,项目肯定需要特殊权限用户
# 注意这里的keyMatch跟regexMatch很重要!!!
m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act) || r.sub == "root"
此时你的csv文件可以类似于,权限配置起来会轻松许多,详见函数
p alice /alice_data/* GET
p alice /alice_data/resource1 POST
p bob /alice_data/resource2 GET
p bob /bob_data/* POST
p cathy /cathy_data (GET)|(POST)
由于casbin、gorm都有不同版本,因此引用的包一定要对上!!!
casbin.go
import (
"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v3"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
const (
// 刚才的rbac配置文件路径
configName = "./configs/rbac_model.conf"
)
var (
enforcer *casbin.Enforcer
errErrorPermission = errors.New("权限有误")
)
func InitCasbin() {
// 这里填入自己的"gorm.io/gorm"的db链接,而不是jinzhu/gorm的,会对不上
adapter, err := gormadapter.NewAdapterByDB(*gorm.DB)
if err != nil {
panic(err)
}
enforcer, err = casbin.NewEnforcer(configName, adapter)
if err != nil {
panic(err)
}
enforcer.EnableLog(false)
err = enforcer.LoadPolicy()
if err != nil {
panic(err)
}
}
casbin启动默认会在数据库下新建一张casbin_rule表,如果创建有问题,可能是默认引擎是MyISAM,而需要用InnoDB,可以显示的AutoMigrate
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&gormadapter.CasbinRule{})
在casbin_rule表中可以定义某些用户加入组,然后以“组”概念去匹配权限,但是这样你的user_message表跟user_role表等于直接用casbin_rule里的定义了,或者需要做关联关系,后面新增用户加权限等等是在操作casbin_rule表的。实际情况下不合理,因此还是自己定义好user_message表跟user_role表,并维护好这两个表多对多关系即可,而casbin的实体验证直接验证“权限”这个概念即可,因此casbin_rule表仅需要保留Policie信息即可
casbin_rule表
# 注意get要小写!
INSERT INTO `casbin_rule` (`ptype`,`v0`,`v1`,`v2`) VALUES ('p','dev','/api/dev/*','get');
casbin.go
func CasbinMiddleWare() func(c *gin.Context) {
return func(c *gin.Context) {
// 白名单下url不验证
for _, whiteUrl := range whiteList {
if strings.Contains(c.Request.URL.String(), whiteUrl) {
c.Next()
return
}
}
username := c.GetString("username")
// 换成自己的角色权限字段
iuserRoles, exists := c.Get("userRoles")
zap.L().Debug("c.Get", zap.String("username", username), zap.Any("iuserRoles", iuserRoles))
if username == "" || !exists {
handlerbase.BuildErrorNilResponse(c, errErrorAuth)
c.Abort()
return
}
p := c.Request.URL.Path
m := c.Request.Method
zap.L().Debug("Request", zap.String("p", p), zap.String("m", m))
userRoles := iuserRoles.([]model.UserRole)
for _, userRole := range userRoles {
// act实体验证该权限名称!
hit, err := enforcer.Enforce(userRole.RoleName, p, m)
if err != nil || !hit {
continue
} else {
c.Next()
return
}
}
handlerbase.BuildErrorNilResponse(c, errErrorPermission)
c.Abort()
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端