一,安装casbin
1,casbin项目代码的地址
2,为go安装casbin
liuhongdi@ku:~$ go get -u github.com/casbin/casbin/v2
gorm-adapter代码地址:
安装gorm-adapter
liuhongdi@ku:~$ go get -u github.com/casbin/gorm-adapter/v3
4,为兼容gorm-adapter,我们更换了gorm的版本,
安装命令:
liuhongdi@ku:~$ go get -u gorm.io/gorm
说明:csv存储只适合于不需要对规则进行管理的权限设计,
所以我们在这里使用数据库来存储规则
说明:刘宏缔的go森林是一个专注golang的博客,
网站:https://blog.imgtouch.com
原文: go语言web开发系列之十二:gin框架通过casbin实现rbac权限设计(mysql存储规则) – 架构森林
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,演示项目的相关信息
1,项目地址
GitHub - liuhongdi/digv12: gin框架使用casbin做用户权限校验(mysql存储)
2,项目功能说明:
/admin/* :只有role为 superAdmin时可访问
/article/* : role为superAdmin/user时均可访问
/home/*: role为任何用户时均可访问
3,项目结构:如图:
三,配置文件说明:
1,config/rbac_model.conf
# Request definition 自定义请求的格式
[request_definition]
r = sub, obj, act
# Policy definition 策略定义
[policy_definition]
p = sub, obj, act
# Policy effect
[policy_effect]
e = some(where (p.eft == allow))
# Matchers
[matchers]
#m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
m = (r.sub == p.sub || p.sub == "*") && keyMatch(r.obj,p.obj) && (r.act == p.act || p.act == "*")
2,mysql数据表:
说明:此数据表由casbin的gorm-adapter自动创建,我们只需要插入数据即可:
sql:
INSERT INTO `casbin_rule` (`id`, `p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES
(3, 'p', '*', '/home/*', '*', NULL, NULL, NULL),
(2, 'p', 'superAdmin', '/admin/*', '*', NULL, NULL, NULL),
(1, 'p', 'superAdmin', '/article/*', '*', NULL, NULL, NULL),
(4, 'p', 'user', '/article/*', '*', NULL, NULL, NULL);
四,go代码说明
1,homeController.go
package controller
import (
"github.com/gin-gonic/gin"
"github.com/liuhongdi/digv12/pkg/result"
)
type HomeController struct{}
func NewHomeController() HomeController {
return HomeController{}
}
//首页,任何人可访问,不登录也可访问
func (a *HomeController) Home(c *gin.Context) {
resultRes := result.NewResult(c)
resultRes.Success("this is home page");
return
}
2,adminController.go
package controller
import (
"github.com/gin-gonic/gin"
"github.com/liuhongdi/digv12/pkg/result"
)
type HomeController struct{}
func NewHomeController() HomeController {
return HomeController{}
}
//首页,任何人可访问,不登录也可访问
func (a *HomeController) Home(c *gin.Context) {
resultRes := result.NewResult(c)
resultRes.Success("this is home page");
return
}
3,ArticleController.go
package controller
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/liuhongdi/digv12/pkg/page"
"github.com/liuhongdi/digv12/pkg/result"
"github.com/liuhongdi/digv12/pkg/validCheck"
"github.com/liuhongdi/digv12/request"
"github.com/liuhongdi/digv12/service"
)
type ArticleController struct{}
func NewArticleController() ArticleController {
return ArticleController{}
}
//得到一篇文章的详情
func (a *ArticleController) GetOne(c *gin.Context) {
result := result.NewResult(c)
param := request.ArticleRequest{ID: validCheck.StrTo(c.Param("id")).MustUInt64()}
valid, errs := validCheck.BindAndValid(c, ¶m)
if !valid {
result.Error(400,errs.Error())
return
}
if (param.ID == 100) {
var z int = 0
var i int = 100 / z
fmt.Println("i:%i",i)
}
articleOne,err := service.GetOneArticle(param.ID);
if err != nil {
result.Error(404,"数据查询错误")
} else {
result.Success(&articleOne);
}
return
}
4,global/casbin.go
package global
import (
"fmt"
"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v3"
"log"
"os"
)
var (
Enforcer *casbin.Enforcer
)
//创建casbin的enforcer
func SetupCasbinEnforcer() (error) {
a, err := gormadapter.NewAdapterByDB(DBLink)
if (err != nil) {
log.Fatalf("gormadapter.NewAdapterByDB err: %v", err)
}
dir, _ := os.Getwd()
modelPath := dir + "/config/rbac_model.conf"
//csvPath := dir + "/config/rbac2.csv"
fmt.Println("modelPath:"+modelPath);
//fmt.Println("csvPath:"+csvPath);
var errC error
Enforcer, errC = casbin.NewEnforcer(modelPath, a)
//fmt.Printf("RBAC test start\n") // output for debug
if (errC != nil) {
//fmt.Println(errC)
log.Fatalf("SetupCasbinEnforcer err: %v", errC)
return errC
} else {
Enforcer.LoadPolicy()
Enforcer.EnableLog(true)
return nil
}
}
5,main.go
package main
import (
"github.com/gin-gonic/gin"
"github.com/liuhongdi/digv12/global"
"github.com/liuhongdi/digv12/router"
"log"
)
//init
func init() {
//setting
err := global.SetupSetting()
if err != nil {
log.Fatalf("init.setupSetting err: %v", err)
}
//logger
err = global.SetupLogger()
if err != nil {
log.Fatalf("init.SetupLogger err: %v", err)
}
//access logger
err = global.SetupAccessLogger()
if err != nil {
log.Fatalf("init.SetupAccessLogger err: %v", err)
}
//db
err = global.SetupDBLink()
if err != nil {
log.Fatalf("init.SetupLogger err: %v", err)
global.Logger.Fatalf("init.setupDBEngine err: %v", err)
}
//casbin
err = global.SetupCasbinEnforcer()
if err != nil {
log.Fatalf("init.SetupCasbinEnforcer err: %v", err)
global.Logger.Fatalf("init.SetupCasbinEnforcer err: %v", err)
}
global.Logger.Infof("------应用init结束")
//global.Logger.
}
func main() {
global.Logger.Infof("------应用main函数开始")
//设置运行模式
gin.SetMode(global.ServerSetting.RunMode)
//引入路由
r := router.Router()
//run
r.Run(":"+global.ServerSetting.HttpPort)
}
说明:注意casbin的初始化要放到mysql之后
6,middleware/permission.go
package middleware
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/liuhongdi/digv12/global"
"github.com/liuhongdi/digv12/pkg/result"
)
func PermissionMiddleWare() gin.HandlerFunc {
return func(c *gin.Context) {
// 请求的path
p := c.Request.URL.Path
// 请求的方法
m := c.Request.Method
role:="superAdmin"
//role:="user"
//role:="guest"
fmt.Println("role:"+role)
fmt.Println("path:"+p)
fmt.Println("method:"+m)
// 检查用户权限
isPass, err := global.Enforcer.Enforce(role, p, m)
if err != nil {
resultRes := result.NewResult(c)
resultRes.Error(2005,err.Error())
return
}
if isPass {
c.Next()
} else {
resultRes := result.NewResult(c)
resultRes.Error(2006,"无访问权限")
return
}
}
}
7,其他相关代码可访问github
五,测试效果
1,middleware/permission.go中,
role:="guest"
访问:
http://127.0.0.1:8000/home/home
返回:
访问:
http://127.0.0.1:8000/article/getone/2
返回:
访问:
http://127.0.0.1:8000/admin/admin
返回:
2,middleware/permission.go中,
role:="user"
访问:
http://127.0.0.1:8000/home/home
返回:
访问:
http://127.0.0.1:8000/article/getone/2
返回:
访问:
http://127.0.0.1:8000/admin/admin
返回:
3,middleware/permission.go中,
role:="superAdmin"
访问:
http://127.0.0.1:8000/home/home
返回:
访问:
http://127.0.0.1:8000/article/getone/2
返回:
访问:
http://127.0.0.1:8000/admin/admin
返回:
六,查看库的版本:
module github.com/liuhongdi/digv12
go 1.15
require (
github.com/casbin/casbin/v2 v2.17.0
github.com/casbin/gorm-adapter/v3 v3.0.4
github.com/gin-gonic/gin v1.6.3
github.com/go-playground/universal-translator v0.17.0
github.com/go-playground/validator/v10 v10.2.0
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
github.com/magiconair/properties v1.8.4 // indirect
github.com/mitchellh/mapstructure v1.3.3 // indirect
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/afero v1.4.1 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.7.1
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.16.0
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
golang.org/x/text v0.3.4 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
gorm.io/driver/mysql v1.0.1
gorm.io/gorm v1.20.7
)