• gin casbin xorm vue-admin权限认证。


    1、因为用到是gin所以直接指定rbac吧。

    一般都是使用:角色,操作路径,操作类型来做权限。如果还要弄更多,这里就不涉及更多了

    首先配置文件

    [request_definition]
    r = sub, obj, act
    
    [policy_definition]
    p = sub, obj, act
    
    [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 == "*")
    

    2、从数据库加载角色配置

    package main
    
    import (
    	"github.com/casbin/casbin/v2"
    	_ "github.com/lib/pq"
    
    	"github.com/casbin/xorm-adapter"
    )
    
    func main() {
    	// Initialize a Xorm adapter and use it in a Casbin enforcer:
    	// The adapter will use the Postgres database named "casbin".
    	// If it doesn't exist, the adapter will create it automatically.
    	a, _ := xormadapter.NewAdapter("postgres", "user=postgres_username password=postgres_password host=127.0.0.1 port=5432 sslmode=disable") // Your driver and data source.
    
    	// Or you can use an existing DB "abc" like this:
    	// The adapter will use the table named "casbin_rule".
    	// If it doesn't exist, the adapter will create it automatically.
    	// a := xormadapter.NewAdapter("postgres", "dbname=abc user=postgres_username password=postgres_password host=127.0.0.1 port=5432 sslmode=disable", true)
    
    	e, _ := casbin.NewEnforcer("../examples/rbac_model.conf", a)
    
    	// Load the policy from DB.
    	e.LoadPolicy()
    }
    

     上面这个是官方提供的从数据加载权限配置的案例。里面会给自动生成数据库,自动生成表。

        那么作为一个要集成到自己项目里面的功能,有一个表跟自己的表。。。nb_开头太格格不入了。所以可以拿它出来进行改写。

    // Copyright 2017 The casbin Authors. All Rights Reserved.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //      http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    package utils
    
    import (
    	"errors"
    	model2 "notebooks/model"
    	"runtime"
    	"strings"
    
    	"github.com/casbin/casbin/v2/model"
    	"github.com/casbin/casbin/v2/persist"
    	"github.com/lib/pq"
    	"github.com/xormplus/xorm"
    )
    
    // Adapter represents the Xorm adapter for policy storage.
    type Adapter struct {
    	driverName     string
    	dataSourceName string
    	dbSpecified    bool
    	engine         *xorm.Engine
    }
    
    // finalizer is the destructor for Adapter.
    func finalizer(a *Adapter) {
    	err := a.engine.Close()
    	if err != nil {
    		panic(err)
    	}
    }
    
    // NewAdapter is the constructor for Adapter.
    // dbSpecified is an optional bool parameter. The default value is false.
    // It's up to whether you have specified an existing DB in dataSourceName.
    // If dbSpecified == true, you need to make sure the DB in dataSourceName exists.
    // If dbSpecified == false, the adapter will automatically create a DB named "casbin".
    func NewAdapter() (*Adapter, error) {
    	a := &Adapter{}
    	// Open the DB, create it if not existed.
    	err := a.open()
    	if err != nil {
    		return nil, err
    	}
    
    	// Call the destructor when the object is released.
    	runtime.SetFinalizer(a, finalizer)
    
    	return a, nil
    }
    //通过已有的engine生成
    func NewAdapterByEngine(engine *xorm.Engine) (*Adapter, error) {
    	a := &Adapter{
    		engine: engine,
    	}
    
    	err := a.createTable()
    	if err != nil {
    		return nil, err
    	}
    
    	return a, nil
    }
    //生成数据库
    func (a *Adapter) createDatabase() (err error) {
    
    	if a.driverName == "postgres" {
    		if _, err = AppEngine.Exec("CREATE DATABASE casbin"); err != nil {
    			// 42P04 is	duplicate_database
    			if pqerr, ok := err.(*pq.Error); ok && pqerr.Code == "42P04" {
    				AppEngine.Close()
    				return nil
    			}
    		}
    	} else if a.driverName != "sqlite3" {
    		_, err = AppEngine.Exec("CREATE DATABASE IF NOT EXISTS casbin")
    	}
    	if err != nil {
    		AppEngine.Close()
    		return err
    	}
    
    	return AppEngine.Close()
    }
    
    func (a *Adapter) open() error {
    	a.engine = AppEngine
    
    	return a.createTable()
    }
    
    func (a *Adapter) close() error {
    	err := a.engine.Close()
    	if err != nil {
    		return err
    	}
    
    	a.engine = nil
    	return nil
    }
    
    func (a *Adapter) createTable() error {
    	return a.engine.Sync2(new(model2.NbCasbinRule))
    }
    
    func (a *Adapter) dropTable() error {
    	return a.engine.DropTables(new(model2.NbCasbinRule))
    }
    
    //原生加载一条权限
    func loadPolicyLine(line *model2.NbCasbinRule, model model.Model) {
    	const prefixLine = ", "
    	var sb strings.Builder
    
    	sb.WriteString(line.PType)
    	if len(line.V0) > 0 {
    		sb.WriteString(prefixLine)
    		sb.WriteString(line.V0)
    	}
    	if len(line.V1) > 0 {
    		sb.WriteString(prefixLine)
    		sb.WriteString(line.V1)
    	}
    	if len(line.V2) > 0 {
    		sb.WriteString(prefixLine)
    		sb.WriteString(line.V2)
    	}
    	if len(line.V3) > 0 {
    		sb.WriteString(prefixLine)
    		sb.WriteString(line.V3)
    	}
    	if len(line.V4) > 0 {
    		sb.WriteString(prefixLine)
    		sb.WriteString(line.V4)
    	}
    	if len(line.V5) > 0 {
    		sb.WriteString(prefixLine)
    		sb.WriteString(line.V5)
    	}
    
    	persist.LoadPolicyLine(sb.String(), model)
    }
    
    // 从数据库查询权限
    func (a *Adapter) LoadPolicy(model model.Model) error {
    	var lines []*model2.NbCasbinRule
    	if err := a.engine.Find(&lines); err != nil {
    		return err
    	}
       //一条一条地加载
    	for _, line := range lines {
    		loadPolicyLine(line, model)
    	}
    
    	return nil
    }
    
    //这个是配置一条权限,返回一条数据
    func savePolicyLine(ptype string, rule []string, colId int) *model2.NbCasbinRule {
    	line := &model2.NbCasbinRule{PType: ptype}
    
    	l := len(rule)
    	if l > 0 {
    		line.V0 = rule[0]
    	}
    	if l > 1 {
    		line.V1 = rule[1]
    	}
    	if l > 2 {
    		line.V2 = rule[2]
    	}
    	if l > 3 {
    		line.V3 = rule[3]
    	}
    	if l > 4 {
    		line.V4 = rule[4]
    	}
    	if l > 5 {
    		line.V5 = rule[5]
    	}
        line.ColId=colId
    	return line
    }
    
    // 这个是将文件里写好的配置文件,写入数据库不能使用
    func (a *Adapter) SavePolicy(model model.Model) error {
    	if 1==1{
    		return errors.New("不能使用本方法")
    	}
    	return nil
    	/*
    	err := a.dropTable()
    	if err != nil {
    		return err
    	}
    	err = a.createTable()
    	if err != nil {
    		return err
    	}
    
    	var lines []*model2.NbCasbinRule
    
    	for ptype, ast := range model["p"] {
    		for _, rule := range ast.Policy {
    			line := savePolicyLine(ptype, rule)
    			lines = append(lines, line)
    		}
    	}
    
    	for ptype, ast := range model["g"] {
    		for _, rule := range ast.Policy {
    			line := savePolicyLine(ptype, rule)
    			lines = append(lines, line)
    		}
    	}
    
    	_, err = a.engine.Insert(&lines)
    	return err
    	*/
    }
    
    // 添加一条权限,但是只是添加,没有入配置的,要重新使用loadPolicy(看情况处理,后期可能要做一下性能处理,再加载)
    func (a *Adapter) AddPolicyNew(sec string, ptype string, rule []string,colId int) error {
    	line := savePolicyLine(ptype, rule,colId)
    	_, err := a.engine.Insert(line)
    	return err
    }
    // 添加一条权限,但是只是添加,没有入配置的,要重新使用loadPolicy(看情况处理,后期可能要做一下性能处理,再加载)
    func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) error {
    	line := savePolicyLine(ptype, rule,0)
    	_, err := a.engine.Insert(line)
    	return err
    }
    // 删除一条权限,同样没有入配置(看情况处理,后期可能要做一下性能处理,再加载)
    func (a *Adapter) RemovePolicyNew(sec string, ptype string, rule []string,colId int) error {
    	line := savePolicyLine(ptype, rule,colId)
    	_, err := a.engine.Delete(line)
    	return err
    }
    // 删除一条权限,同样没有入配置(看情况处理,后期可能要做一下性能处理,再加载)
    func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string) error {
    	line := savePolicyLine(ptype, rule,0)
    	_, err := a.engine.Delete(line)
    	return err
    }
    
    // 根据配置删除相应的一条权限(少用吧),同样要重新加载
    func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error {
    	if 1==1{
    		return errors.New("不能使用本方法")
    	}
    	line := &model2.NbCasbinRule{PType: ptype}
    
    	idx := fieldIndex + len(fieldValues)
    	if fieldIndex <= 0 && idx > 0 {
    		line.V0 = fieldValues[0-fieldIndex]
    	}
    	if fieldIndex <= 1 && idx > 1 {
    		line.V1 = fieldValues[1-fieldIndex]
    	}
    	if fieldIndex <= 2 && idx > 2 {
    		line.V2 = fieldValues[2-fieldIndex]
    	}
    	if fieldIndex <= 3 && idx > 3 {
    		line.V3 = fieldValues[3-fieldIndex]
    	}
    	if fieldIndex <= 4 && idx > 4 {
    		line.V4 = fieldValues[4-fieldIndex]
    	}
    	if fieldIndex <= 5 && idx > 5 {
    		line.V5 = fieldValues[5-fieldIndex]
    	}
    
    	_, err := a.engine.Delete(line)
    	return err
    }
    

    在这里,直接把里面的生成结构写成与自己风格一致的struct,并放在model里,这样,它就不会生成原版的表,而是生成model里的表了,在里面使用到的engine可以使用自己全局的定义的db engine。保证配置数据库连接只有一个地方。

    里面的方法基本上根据自己的业务写在自己的service里,并不一定要用它原来的写法。

    3、到这里,已经可以从数据库里加载自己想要的权限了。那么,要怎么放入权限呢

    casbinrule原表有,ptype,v0,v1,v2,v3,v4,v5.目前只使用到ptype,v0,v1,v2

    ptype写死为p,v0为角色,v1为操作路径v2为方式,如:ptype:p,v0:supperAdmin,v1:/money/all_in_my_card,v2:POST

    说明supperAdmin有路径/money/all_in_my_card操作post的权限

    根据自己的业务要求,把对应的数据生成放到表后。下面使用中间件来进行验证

    func CheckPermission() gin.HandlerFunc {
    	return func(c *gin.Context) {
    		//根据上下文获取载荷claims 从claims获得role
    		strClaims, has := c.Get("claims")
    		if has {
    			claims := strClaims.(*CustomClaims)
    			role := claims.Role
    			if len(role) < 3 {
    				c.JSON(http.StatusOK, gin.H{
    					"errno":  403,
    					"errmsg": "验证权限出错",
    				})
    				c.Abort()
    				return
    			}
    			rolsString := role[1 : len(role)-1]
    			roleArr := strings.Split(rolsString, ",")
    			var fitErr error
    			var has bool
    			var err error
    			for _, oneRole := range roleArr {
    				has, err = utils.CasbinEn.Enforce( oneRole, c.Request.URL.Path, c.Request.Method)
    				if err != nil {
    					fitErr = err
    					break
    				}
    				if has {
    					break
    				}
    			}
    			if fitErr != nil {
    				c.JSON(http.StatusOK, gin.H{
    					"errno":  403,
    					"errmsg": "验证权限出错",
    				})
    				c.Abort()
    				return
    			}
    			if has {
    				c.Next()
    			} else {
    				c.JSON(http.StatusOK, gin.H{
    					"errno": 403,
    					"msg":   "很抱歉您没有此权限",
    				})
    				c.Abort()
    				return
    			}
    		} else {
    			c.Next()
    		}
    	}
    }
    

      

    4、上面是处理好的后台权限的控制。(需搭配jwt验证一起使用)。那么vue-admin里怎么控制呢.

    vue-admin有一个perms的权限处理。在后台生成"perms":["GET /sys/admin","GET /sys/log","GET /sys/os","GET /sys/role"]给到前台就行。

    其实就是根据用户的角色,查询casbinrule里的v1,v2,组成json list返回就可以。

     

    上面是这段时间改写casbin权限用到的一点看法,以及实际的步骤。  

  • 相关阅读:
    按照分隔符拆分单元格
    Centos7通过reposync同步国内yum源-搭建局域网内网本地Yum源
    局域网vsftpd服务搭建自定义的yum仓库
    centos6编译安装ImageMagick
    tree命令常用参数
    常用mount命令
    十二月四学习报告
    十二月三学习报告
    十二月一学习报告
    十一月三十学习报告
  • 原文地址:https://www.cnblogs.com/bfyang5130/p/12896083.html
Copyright © 2020-2023  润新知