From 7454d077b9080ec035ba75b4944b004fd4935c61 Mon Sep 17 00:00:00 2001 From: yxh Date: Wed, 5 Feb 2020 18:51:57 +0800 Subject: [PATCH] =?UTF-8?q?casbin=E6=95=B4=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- app/controller/admin/auth.go | 29 +- app/model/casbin_rule/casbin_rule_entity.go | 58 +++ app/model/casbin_rule/casbin_rule_model.go | 367 ++++++++++++++++++ app/service/auth_service/auth_rule.go | 51 +++ app/service/casbin_adapter_service/adapter.go | 229 +++++++++++ config/casbin_conf/rbac_model.conf | 14 + config/casbin_conf/rbac_policy.csv | 5 + config/config.toml | 8 +- 9 files changed, 761 insertions(+), 3 deletions(-) create mode 100644 app/model/casbin_rule/casbin_rule_entity.go create mode 100644 app/model/casbin_rule/casbin_rule_model.go create mode 100644 app/service/casbin_adapter_service/adapter.go create mode 100644 config/casbin_conf/rbac_model.conf create mode 100644 config/casbin_conf/rbac_policy.csv diff --git a/.gitignore b/.gitignore index 980a6c4..860f657 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ cbuild main .vscode go.sum -*.exe \ No newline at end of file +*.exe +tmp \ No newline at end of file diff --git a/app/controller/admin/auth.go b/app/controller/admin/auth.go index f98e73a..13461b8 100644 --- a/app/controller/admin/auth.go +++ b/app/controller/admin/auth.go @@ -104,8 +104,35 @@ func (c *Auth) DeleteMenu(r *ghttp.Request) { func (c *Auth) AddGroup(r *ghttp.Request) { //添加操作 if r.Method == "POST" { + /*enforcer,err:=casbin_adapter_service.GetEnforcer() + if err!=nil{ + g.Log().Error(err.Error()) + response.FailJson(true, r, "权限适配器获取失败") + } + ss:=enforcer.GetPolicy()*/ + //获取表单提交的数据 res := r.GetFormMap() - response.SusJson(true, r, "添加成功", res) + //添加角色获取添加的id + tx, err := g.DB("default").Begin() //开启事务 + if err != nil { + g.Log().Error(err) + response.FailJson(true, r, "事务处理失败") + } + //插入角色 + insertId, err := auth_service.AddRole(tx, res) + if err != nil { + tx.Rollback() //回滚 + response.FailJson(true, r, err.Error()) + } + //添加角色权限 + err = auth_service.AddRoleRule(tx, res["rule"], insertId) + if err != nil { + tx.Rollback() //回滚 + g.Log().Error(err.Error()) + response.FailJson(true, r, "添加用户组失败") + } + tx.Commit() + response.SusJson(true, r, "添加用户组成功", insertId, res) } //获取父级组 err, pList := auth_service.GetRoleList("") diff --git a/app/model/casbin_rule/casbin_rule_entity.go b/app/model/casbin_rule/casbin_rule_entity.go new file mode 100644 index 0000000..116111e --- /dev/null +++ b/app/model/casbin_rule/casbin_rule_entity.go @@ -0,0 +1,58 @@ +// ========================================================================== +// This is auto-generated by gf cli tool. You may not really want to edit it. +// ========================================================================== + +package casbin_rule + +import ( + "database/sql" + "github.com/gogf/gf/database/gdb" +) + +// Entity is the golang structure for table casbin_rule. +type Entity struct { + Ptype string `orm:"ptype" json:"ptype"` // + V0 string `orm:"v0" json:"v_0"` // + V1 string `orm:"v1" json:"v_1"` // + V2 string `orm:"v2" json:"v_2"` // + V3 string `orm:"v3" json:"v_3"` // + V4 string `orm:"v4" json:"v_4"` // + V5 string `orm:"v5" json:"v_5"` // +} + +// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers +// the data and where attributes for empty values. +func (r *Entity) OmitEmpty() *arModel { + return Model.Data(r).OmitEmpty() +} + +// Inserts does "INSERT...INTO..." statement for inserting current object into table. +func (r *Entity) Insert() (result sql.Result, err error) { + return Model.Data(r).Insert() +} + +// Replace does "REPLACE...INTO..." statement for inserting current object into table. +// If there's already another same record in the table (it checks using primary key or unique index), +// it deletes it and insert this one. +func (r *Entity) Replace() (result sql.Result, err error) { + return Model.Data(r).Replace() +} + +// Save does "INSERT...INTO..." statement for inserting/updating current object into table. +// It updates the record if there's already another same record in the table +// (it checks using primary key or unique index). +func (r *Entity) Save() (result sql.Result, err error) { + return Model.Data(r).Save() +} + +// Update does "UPDATE...WHERE..." statement for updating current object from table. +// It updates the record if there's already another same record in the table +// (it checks using primary key or unique index). +func (r *Entity) Update() (result sql.Result, err error) { + return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update() +} + +// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table. +func (r *Entity) Delete() (result sql.Result, err error) { + return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete() +} diff --git a/app/model/casbin_rule/casbin_rule_model.go b/app/model/casbin_rule/casbin_rule_model.go new file mode 100644 index 0000000..3123c49 --- /dev/null +++ b/app/model/casbin_rule/casbin_rule_model.go @@ -0,0 +1,367 @@ +// ========================================================================== +// This is auto-generated by gf cli tool. You may not really want to edit it. +// ========================================================================== + +package casbin_rule + +import ( + "database/sql" + "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/frame/g" + "time" +) + +// arModel is a active record design model for table casbin_rule operations. +type arModel struct { + M *gdb.Model +} + +var ( + // Table is the table name of casbin_rule. + Table = "casbin_rule" + // Model is the model object of casbin_rule. + Model = &arModel{g.DB("default").Table(Table).Safe()} +) + +// FindOne is a convenience method for Model.FindOne. +// See Model.FindOne. +func FindOne(where ...interface{}) (*Entity, error) { + return Model.FindOne(where...) +} + +// FindAll is a convenience method for Model.FindAll. +// See Model.FindAll. +func FindAll(where ...interface{}) ([]*Entity, error) { + return Model.FindAll(where...) +} + +// FindValue is a convenience method for Model.FindValue. +// See Model.FindValue. +func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) { + return Model.FindValue(fieldsAndWhere...) +} + +// FindCount is a convenience method for Model.FindCount. +// See Model.FindCount. +func FindCount(where ...interface{}) (int, error) { + return Model.FindCount(where...) +} + +// Insert is a convenience method for Model.Insert. +func Insert(data ...interface{}) (result sql.Result, err error) { + return Model.Insert(data...) +} + +// Replace is a convenience method for Model.Replace. +func Replace(data ...interface{}) (result sql.Result, err error) { + return Model.Replace(data...) +} + +// Save is a convenience method for Model.Save. +func Save(data ...interface{}) (result sql.Result, err error) { + return Model.Save(data...) +} + +// Update is a convenience method for Model.Update. +func Update(dataAndWhere ...interface{}) (result sql.Result, err error) { + return Model.Update(dataAndWhere...) +} + +// Delete is a convenience method for Model.Delete. +func Delete(where ...interface{}) (result sql.Result, err error) { + return Model.Delete(where...) +} + +// As sets an alias name for current table. +func (m *arModel) As(as string) *arModel { + return &arModel{m.M.As(as)} +} + +// TX sets the transaction for current operation. +func (m *arModel) TX(tx *gdb.TX) *arModel { + return &arModel{m.M.TX(tx)} +} + +// Master marks the following operation on master node. +func (m *arModel) Master() *arModel { + return &arModel{m.M.Master()} +} + +// Slave marks the following operation on slave node. +// Note that it makes sense only if there's any slave node configured. +func (m *arModel) Slave() *arModel { + return &arModel{m.M.Slave()} +} + +// LeftJoin does "LEFT JOIN ... ON ..." statement on the model. +func (m *arModel) LeftJoin(joinTable string, on string) *arModel { + return &arModel{m.M.LeftJoin(joinTable, on)} +} + +// RightJoin does "RIGHT JOIN ... ON ..." statement on the model. +func (m *arModel) RightJoin(joinTable string, on string) *arModel { + return &arModel{m.M.RightJoin(joinTable, on)} +} + +// InnerJoin does "INNER JOIN ... ON ..." statement on the model. +func (m *arModel) InnerJoin(joinTable string, on string) *arModel { + return &arModel{m.M.InnerJoin(joinTable, on)} +} + +// Fields sets the operation fields of the model, multiple fields joined using char ','. +func (m *arModel) Fields(fields string) *arModel { + return &arModel{m.M.Fields(fields)} +} + +// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','. +func (m *arModel) FieldsEx(fields string) *arModel { + return &arModel{m.M.FieldsEx(fields)} +} + +// Option sets the extra operation option for the model. +func (m *arModel) Option(option int) *arModel { + return &arModel{m.M.Option(option)} +} + +// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers +// the data and where attributes for empty values. +func (m *arModel) OmitEmpty() *arModel { + return &arModel{m.M.OmitEmpty()} +} + +// Filter marks filtering the fields which does not exist in the fields of the operated table. +func (m *arModel) Filter() *arModel { + return &arModel{m.M.Filter()} +} + +// Where sets the condition statement for the model. The parameter can be type of +// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times, +// multiple conditions will be joined into where statement using "AND". +// Eg: +// Where("uid=10000") +// Where("uid", 10000) +// Where("money>? AND name like ?", 99999, "vip_%") +// Where("uid", 1).Where("name", "john") +// Where("status IN (?)", g.Slice{1,2,3}) +// Where("age IN(?,?)", 18, 50) +// Where(User{ Id : 1, UserName : "john"}) +func (m *arModel) Where(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.Where(where, args...)} +} + +// And adds "AND" condition to the where statement. +func (m *arModel) And(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.And(where, args...)} +} + +// Or adds "OR" condition to the where statement. +func (m *arModel) Or(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.Or(where, args...)} +} + +// Group sets the "GROUP BY" statement for the model. +func (m *arModel) Group(groupBy string) *arModel { + return &arModel{m.M.Group(groupBy)} +} + +// Order sets the "ORDER BY" statement for the model. +func (m *arModel) Order(orderBy string) *arModel { + return &arModel{m.M.Order(orderBy)} +} + +// Limit sets the "LIMIT" statement for the model. +// The parameter can be either one or two number, if passed two number is passed, +// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]" +// statement. +func (m *arModel) Limit(limit ...int) *arModel { + return &arModel{m.M.Limit(limit...)} +} + +// Offset sets the "OFFSET" statement for the model. +// It only makes sense for some databases like SQLServer, PostgreSQL, etc. +func (m *arModel) Offset(offset int) *arModel { + return &arModel{m.M.Offset(offset)} +} + +// Page sets the paging number for the model. +// The parameter is started from 1 for paging. +// Note that, it differs that the Limit function start from 0 for "LIMIT" statement. +func (m *arModel) Page(page, limit int) *arModel { + return &arModel{m.M.Page(page, limit)} +} + +// Batch sets the batch operation number for the model. +func (m *arModel) Batch(batch int) *arModel { + return &arModel{m.M.Batch(batch)} +} + +// Cache sets the cache feature for the model. It caches the result of the sql, which means +// if there's another same sql request, it just reads and returns the result from cache, it +// but not committed and executed into the database. +// +// If the parameter < 0, which means it clear the cache with given . +// If the parameter = 0, which means it never expires. +// If the parameter > 0, which means it expires after . +// +// The optional parameter is used to bind a name to the cache, which means you can later +// control the cache like changing the or clearing the cache with specified . +// +// Note that, the cache feature is disabled if the model is operating on a transaction. +func (m *arModel) Cache(expire time.Duration, name ...string) *arModel { + return &arModel{m.M.Cache(expire, name...)} +} + +// Data sets the operation data for the model. +// The parameter can be type of string/map/gmap/slice/struct/*struct, etc. +// Eg: +// Data("uid=10000") +// Data("uid", 10000) +// Data(g.Map{"uid": 10000, "name":"john"}) +// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"}) +func (m *arModel) Data(data ...interface{}) *arModel { + return &arModel{m.M.Data(data...)} +} + +// Insert does "INSERT INTO ..." statement for the model. +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *arModel) Insert(data ...interface{}) (result sql.Result, err error) { + return m.M.Insert(data...) +} + +// Replace does "REPLACE INTO ..." statement for the model. +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *arModel) Replace(data ...interface{}) (result sql.Result, err error) { + return m.M.Replace(data...) +} + +// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model. +// It updates the record if there's primary or unique index in the saving data, +// or else it inserts a new record into the table. +// +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *arModel) Save(data ...interface{}) (result sql.Result, err error) { + return m.M.Save(data...) +} + +// Update does "UPDATE ... " statement for the model. +// +// If the optional parameter is given, the dataAndWhere[0] is the updated +// data field, and dataAndWhere[1:] is treated as where condition fields. +// Also see Model.Data and Model.Where functions. +func (m *arModel) Update(dataAndWhere ...interface{}) (result sql.Result, err error) { + return m.M.Update(dataAndWhere...) +} + +// Delete does "DELETE FROM ... " statement for the model. +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) Delete(where ...interface{}) (result sql.Result, err error) { + return m.M.Delete(where...) +} + +// Count does "SELECT COUNT(x) FROM ..." statement for the model. +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) Count(where ...interface{}) (int, error) { + return m.M.Count(where...) +} + +// All does "SELECT FROM ..." statement for the model. +// It retrieves the records from table and returns the result as []*Entity. +// It returns nil if there's no record retrieved with the given conditions from table. +// +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) All(where ...interface{}) ([]*Entity, error) { + all, err := m.M.All(where...) + if err != nil { + return nil, err + } + var entities []*Entity + if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entities, nil +} + +// One retrieves one record from table and returns the result as *Entity. +// It returns nil if there's no record retrieved with the given conditions from table. +// +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) One(where ...interface{}) (*Entity, error) { + one, err := m.M.One(where...) + if err != nil { + return nil, err + } + var entity *Entity + if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entity, nil +} + +// Value retrieves a specified record value from table and returns the result as interface type. +// It returns nil if there's no record found with the given conditions from table. +// +// If the optional parameter is given, the fieldsAndWhere[0] is the selected fields +// and fieldsAndWhere[1:] is treated as where condition fields. +// Also see Model.Fields and Model.Where functions. +func (m *arModel) Value(fieldsAndWhere ...interface{}) (gdb.Value, error) { + return m.M.Value(fieldsAndWhere...) +} + +// FindOne retrieves and returns a single Record by Model.WherePri and Model.One. +// Also see Model.WherePri and Model.One. +func (m *arModel) FindOne(where ...interface{}) (*Entity, error) { + one, err := m.M.FindOne(where...) + if err != nil { + return nil, err + } + var entity *Entity + if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entity, nil +} + +// FindAll retrieves and returns Result by by Model.WherePri and Model.All. +// Also see Model.WherePri and Model.All. +func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) { + all, err := m.M.FindAll(where...) + if err != nil { + return nil, err + } + var entities []*Entity + if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entities, nil +} + +// FindValue retrieves and returns single field value by Model.WherePri and Model.Value. +// Also see Model.WherePri and Model.Value. +func (m *arModel) FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) { + return m.M.FindValue(fieldsAndWhere...) +} + +// FindCount retrieves and returns the record number by Model.WherePri and Model.Count. +// Also see Model.WherePri and Model.Count. +func (m *arModel) FindCount(where ...interface{}) (int, error) { + return m.M.FindCount(where...) +} + +// Chunk iterates the table with given size and callback function. +func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) { + m.M.Chunk(limit, func(result gdb.Result, err error) bool { + var entities []*Entity + err = result.Structs(&entities) + if err == sql.ErrNoRows { + return false + } + return callback(entities, err) + }) +} diff --git a/app/service/auth_service/auth_rule.go b/app/service/auth_service/auth_rule.go index e933d98..05776b2 100644 --- a/app/service/auth_service/auth_rule.go +++ b/app/service/auth_service/auth_rule.go @@ -1,11 +1,15 @@ package auth_service import ( + "database/sql" "gfast/app/model/auth_rule" "gfast/app/model/role" + "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/util/gconv" + "github.com/gogf/gf/util/gvalid" ) //菜单对象 @@ -84,3 +88,50 @@ func GetRoleList(where string, params ...interface{}) (err error, list g.List) { } return } + +//保存角色信息并返回插入的id +func AddRole(tx *gdb.TX, data map[string]interface{}) (InsId int64, err error) { + if e := checkRoleData(data); e != nil { + err = gerror.New(e.(*gvalid.Error).FirstString()) + return + } + //保存角色信息 + now := gtime.Timestamp() + roleMap := gdb.Map{ + "parent_id": data["parent_id"], + "status": data["status"], + "name": data["name"], + "create_time": now, + "update_time": now, + "list_order": data["list_order"], + "remark": data["remark"], + } + var res sql.Result + res, err = tx.Table(role.Table).Data(roleMap).Save() + if err != nil { + return + } + InsId, _ = res.LastInsertId() + return +} + +func AddRoleRule(tx *gdb.TX, iRule interface{}, roleId int64) (err error) { + rule := iRule.([]interface{}) + for _, v := range rule { + g.Log().Debug(v) + } + return +} + +func checkRoleData(params map[string]interface{}) error { + rules := []string{ + "name@required|length:1,20#请填写角色名称|名称应在:min到:max个字符之间", + "parent_id@integer|min:0#父级ID必须为整数|父级ID必须大于等于0", + } + + e := gvalid.CheckMap(params, rules) + if e != nil { + return e + } + return nil +} diff --git a/app/service/casbin_adapter_service/adapter.go b/app/service/casbin_adapter_service/adapter.go new file mode 100644 index 0000000..711f969 --- /dev/null +++ b/app/service/casbin_adapter_service/adapter.go @@ -0,0 +1,229 @@ +package casbin_adapter_service + +import ( + "fmt" + "gfast/app/model/casbin_rule" + "github.com/casbin/casbin/v2" + "github.com/casbin/casbin/v2/model" + "github.com/casbin/casbin/v2/persist" + "github.com/gogf/gf/frame/g" + "sync" +) + +type Adapter struct{} + +var Enforcer *casbin.SyncedEnforcer +var EnforcerErr error +var once sync.Once + +//获取adapter单例对象 +func GetEnforcer() (*casbin.SyncedEnforcer, error) { + once.Do(func() { + _, EnforcerErr = newAdapter() + }) + return Enforcer, EnforcerErr +} + +//初始化adapter操作 +func newAdapter() (a *Adapter, err error) { + a = new(Adapter) + err = a.initPolicy() + return +} + +func (a *Adapter) initPolicy() error { + // Because the DB is empty at first, + // so we need to load the policy from the file adapter (.CSV) first. + e, err := casbin.NewSyncedEnforcer(g.Cfg().GetString("casbin.modelFile"), + g.Cfg().GetString("casbin.policyFile")) + + if err != nil { + return err + } + + // This is a trick to save the current policy to the DB. + // We can't call e.SavePolicy() because the adapter in the enforcer is still the file adapter. + // The current policy means the policy in the Casbin enforcer (aka in memory). + //err = a.SavePolicy(e.GetModel()) + //if err != nil { + // return err + //} + //set adapter + e.SetAdapter(a) + // Clear the current policy. + e.ClearPolicy() + Enforcer = e + // Load the policy from DB. + err = a.LoadPolicy(e.GetModel()) + if err != nil { + return err + } + return nil +} + +// SavePolicy saves policy to database. +func (a *Adapter) SavePolicy(model model.Model) (err error) { + err = a.dropTable() + if err != nil { + return + } + err = a.createTable() + if err != nil { + return + } + for ptype, ast := range model["p"] { + for _, rule := range ast.Policy { + line := savePolicyLine(ptype, rule) + _, err := casbin_rule.Model.Data(&line).Insert() + if err != nil { + return err + } + } + } + + for ptype, ast := range model["g"] { + for _, rule := range ast.Policy { + line := savePolicyLine(ptype, rule) + _, err := casbin_rule.Model.Data(&line).Insert() + if err != nil { + return err + } + } + } + return +} + +func (a *Adapter) dropTable() (err error) { + _, err = g.DB("default").Exec(fmt.Sprintf("DROP TABLE %s", casbin_rule.Table)) + return +} + +func (a *Adapter) createTable() (err error) { + _, err = g.DB("default").Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (ptype VARCHAR(10), v0 VARCHAR(256), v1 VARCHAR(256), v2 VARCHAR(256), v3 VARCHAR(256), v4 VARCHAR(256), v5 VARCHAR(256))", casbin_rule.Table)) + return +} + +// LoadPolicy loads policy from database. +func (a *Adapter) LoadPolicy(model model.Model) error { + var lines []casbin_rule.Entity + if err := casbin_rule.Model.M.Scan(&lines); err != nil { + return err + } + for _, line := range lines { + loadPolicyLine(line, model) + } + return nil +} + +// AddPolicy adds a policy rule to the storage. +func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) error { + line := savePolicyLine(ptype, rule) + _, err := casbin_rule.Model.M.Data(&line).Insert() + return err +} + +// RemovePolicy removes a policy rule from the storage. +func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string) error { + line := savePolicyLine(ptype, rule) + err := rawDelete(a, line) + return err +} + +// RemoveFilteredPolicy removes policy rules that match the filter from the storage. +func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error { + line := casbin_rule.Entity{} + line.Ptype = ptype + if fieldIndex <= 0 && 0 < fieldIndex+len(fieldValues) { + line.V0 = fieldValues[0-fieldIndex] + } + if fieldIndex <= 1 && 1 < fieldIndex+len(fieldValues) { + line.V1 = fieldValues[1-fieldIndex] + } + if fieldIndex <= 2 && 2 < fieldIndex+len(fieldValues) { + line.V2 = fieldValues[2-fieldIndex] + } + if fieldIndex <= 3 && 3 < fieldIndex+len(fieldValues) { + line.V3 = fieldValues[3-fieldIndex] + } + if fieldIndex <= 4 && 4 < fieldIndex+len(fieldValues) { + line.V4 = fieldValues[4-fieldIndex] + } + if fieldIndex <= 5 && 5 < fieldIndex+len(fieldValues) { + line.V5 = fieldValues[5-fieldIndex] + } + err := rawDelete(a, line) + return err +} + +func loadPolicyLine(line casbin_rule.Entity, model model.Model) { + lineText := line.Ptype + if line.V0 != "" { + lineText += ", " + line.V0 + } + if line.V1 != "" { + lineText += ", " + line.V1 + } + if line.V2 != "" { + lineText += ", " + line.V2 + } + if line.V3 != "" { + lineText += ", " + line.V3 + } + if line.V4 != "" { + lineText += ", " + line.V4 + } + if line.V5 != "" { + lineText += ", " + line.V5 + } + persist.LoadPolicyLine(lineText, model) +} + +func savePolicyLine(ptype string, rule []string) casbin_rule.Entity { + line := casbin_rule.Entity{} + line.Ptype = ptype + if len(rule) > 0 { + line.V0 = rule[0] + } + if len(rule) > 1 { + line.V1 = rule[1] + } + if len(rule) > 2 { + line.V2 = rule[2] + } + if len(rule) > 3 { + line.V3 = rule[3] + } + if len(rule) > 4 { + line.V4 = rule[4] + } + if len(rule) > 5 { + line.V5 = rule[5] + } + return line +} + +func rawDelete(a *Adapter, line casbin_rule.Entity) error { + db := casbin_rule.Model + db.Where("ptype = ?", line.Ptype) + if line.V0 != "" { + db.Where("v0 = ?", line.V0) + } + if line.V1 != "" { + db.Where("v1 = ?", line.V1) + } + if line.V2 != "" { + db.Where("v2 = ?", line.V2) + } + if line.V3 != "" { + db.Where("v3 = ?", line.V3) + } + if line.V4 != "" { + db.Where("v4 = ?", line.V4) + } + if line.V5 != "" { + db.Where("v5 = ?", line.V5) + } + + _, err := db.Delete() + return err +} diff --git a/config/casbin_conf/rbac_model.conf b/config/casbin_conf/rbac_model.conf new file mode 100644 index 0000000..71159e3 --- /dev/null +++ b/config/casbin_conf/rbac_model.conf @@ -0,0 +1,14 @@ +[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) && r.obj == p.obj && r.act == p.act \ No newline at end of file diff --git a/config/casbin_conf/rbac_policy.csv b/config/casbin_conf/rbac_policy.csv new file mode 100644 index 0000000..f93d6df --- /dev/null +++ b/config/casbin_conf/rbac_policy.csv @@ -0,0 +1,5 @@ +p, alice, data1, read +p, bob, data2, write +p, data2_admin, data2, read +p, data2_admin, data2, write +g, alice, data2_admin \ No newline at end of file diff --git a/config/config.toml b/config/config.toml index 9cfa57e..ba280b0 100644 --- a/config/config.toml +++ b/config/config.toml @@ -39,4 +39,10 @@ [logger] path = "./data/log/run_log" level = "all" - stdout = true \ No newline at end of file + stdout = true + +#casbin配置 +[casbin] +modelFile="./config/casbin_conf/rbac_model.conf" +policyFile="./config/casbin_conf/rbac_policy.csv" +