写点什么

[go] 后台管理数据权限控制实现 (无业务修改)

作者:林逸民
  • 2022 年 6 月 03 日
  • 本文字数:3570 字

    阅读完需:约 12 分钟

前言

这篇文章与[ts]后台管理数据权限控制实现(无业务修改)_typescript_林逸民_InfoQ写作社区内容是一样的, 只是语言由typescript(ts)换成了golang(go), 该文章基于扩展[go]mongo工具类_Go_林逸民_InfoQ写作社区来实现无需业务侵入就能实现后台的数据权限控制.

数据库接口

文章就不再贴相关接口的代码了, 具体请看上面的文章.

模型

由于数据库都是mongo, 因此只需将原先ts模型改为go的即可, 另外需要定义一个CRUD的枚举, 大致代码如下:

// 模型接口type IDbModel interface {  GetID() string}
// 管理员权限模型type AdminPermission struct { ID string `bson:"_id" db:"_id"` Permission map[string]map[DbOpValue]interface{}}
func (m AdminPermission) GetID() string { return m.ID}
// 枚举type DbOpValue string
const ( // 增加 DbOpInsert DbOpValue = "c" // 删除 DbOpDelete DbOpValue = "d" // 更新 DbOpUpdate DbOpValue = "u" // 查询 DbOpQuery DbOpValue = "r")
复制代码
IUnitOfWorkRepository - 增删改权限

由于数据库增删改都是由IUnitOfWork管理的, 因此只需要重新实现该接口, 而内部包含mongo版的IUnitOfWork, 大致代码如下:

// 工作单元仓储type unitOfWorkRepository struct {  adminPermissionDbQuery IDbQuery  uow                    IUnitOfWorkRepository  adminID                string  modelOperation         map[string]map[DbOpValue]bool}
// 提交func (m *unitOfWorkRepository) Commit() (err error) { defer func() { m.modelOperation = make(map[string]map[DbOpValue]bool) }()
var adminPermissions []AdminPermission err = m.adminPermissionDbQuery.Where(bson.M{ "_id": m.adminID, }).ToArray(&adminPermissions) if err != nil { return }
if len(adminPermissions) > 0 { for k, v := range m.modelOperation { for ck, _ := range v { if sv, ok := adminPermissions[0].Permission[k]; ok { if _, ok = sv[ck]; ok { return fmt.Errorf("无权限: %s, %d", k, ck) } } } } }
err = m.uow.Commit() return}
// 注冊删除func (m *unitOfWorkRepository) RegisterDelete(entry IDbModel) { m.addModelOperation(entry, DbOpDelete) m.uow.RegisterDelete(entry)}
// 注冊新增func (m *unitOfWorkRepository) RegisterInsert(entry IDbModel) { m.addModelOperation(entry, DbOpInsert) m.uow.RegisterInsert(entry)}
// 注冊更新func (m *unitOfWorkRepository) RegisterUpdate(entry IDbModel) { m.addModelOperation(entry, DbOpUpdate) m.uow.RegisterUpdate(entry)}
// 添加模型操作func (m *unitOfWorkRepository) addModelOperation(entry IDbModel, op DbOpValue) { modelType := reflect.TypeOf(entry) model := modelType.Name() if _, ok := m.modelOperation[model]; !ok { m.modelOperation[model] = make(map[DbOpValue]bool) }
m.modelOperation[model][op] = true}
// 创建工作单元仓储func newUnitOfWorkRepository( adminPermissionDbQuery IDbQuery, uow IUnitOfWorkRepository, adminID string,) IUnitOfWorkRepository { return &unitOfWorkRepository{ adminID: adminID, adminPermissionDbQuery: adminPermissionDbQuery, modelOperation: make(map[string]map[DbOpValue]bool), uow: uow, }}
复制代码
IDbQuery - 查询权限

查询权限的实现跟增删改的实现类似, 而接口则从IUnitOfWork换成了IDbQuery, 大致代码如下:

type dbQuery struct {  adminPermissionDbQuery DbQuery  originDbQuery          IDbQuery  filter                 bson.M  adminID                string  model                  string}
func (m *dbQuery) Count() (count int64, err error) { var filter bson.M if filter, err = m.getFilter(); err != nil { return }
return m.originDbQuery.Where(filter).Count()}
func (m *dbQuery) Order(fields ...string) IDbQuery { m.originDbQuery.Order(fields...) return m}
func (m *dbQuery) OrderByDesc(fields ...string) IDbQuery { m.originDbQuery.OrderByDesc(fields...) return m}
func (m *dbQuery) Skip(v int) IDbQuery { m.originDbQuery.Skip(v) return m}
func (m *dbQuery) Take(v int) IDbQuery { m.originDbQuery.Take(v) return m}
func (m *dbQuery) ToArray(dst interface{}) (err error) { var filter bson.M if filter, err = m.getFilter(); err != nil { return }
err = m.originDbQuery.Where(filter).ToArray(dst) return}
func (m *dbQuery) Where(args ...interface{}) IDbQuery { if len(args) == 0 { return m }
if f, ok := args[0].(bson.M); ok { m.filter = f } return m}
func (m *dbQuery) getFilter() (filter bson.M, err error) { filter = m.filter m.filter = nil
if filter == nil { filter = bson.M{} }
var adminPermissions []AdminPermission err = m.adminPermissionDbQuery.Where(bson.M{ "_id": m.adminID, }).ToArray(&adminPermissions) if err != nil { return }
if len(adminPermissions) > 0 { if v, ok := adminPermissions[0].Permission[m.model]; ok { if cv, ok := v[DbOpQuery]; ok { // 合并条件 var doc bson.M bson.Unmarshal( cv.(primitive.Binary).Data, &doc, ) for sk, sv := range doc { filter[sk] = sv } } } } return}
func newDbQuery( adminPermissionDbQuery IDbQuery, originDbQuery IDbQuery, adminID string, model string,) IDbQuery { return &dbQuery{ adminPermissionDbQuery: adminPermissionDbQuery, originDbQuery: originDbQuery, adminID: adminID, model: model, }}
复制代码
IDbFactory

由于dbQueryunitOfWorkRepository都有根据adminID查询AdminPermission, 因此可以将此段逻辑提取到工厂中以延迟加载的方式复用, dbQueryunitOfWorkRepository的重构代码这里省略了, 其他代码如下:

type dbFactory struct {  mongoDbFactory   IDbFactory  adminID          string  adminPermissions []AdminPermission}
func (m *dbFactory) Db(entry IDbModel, extra ...interface{}) IDbRepository { var uow *unitOfWorkRepository isTx := true underscore.Chain(extra).Each(func(r interface{}, _ int) { if v, ok := r.(*unitOfWorkRepository); ok { uow = v } })
if uow == nil { isTx = false uow = m.Uow().(*unitOfWorkRepository) }
modelType := reflect.TypeOf(entry) return newDbRepository( m.mongoDbFactory.Db(entry).Query(), uow, isTx, modelType.Name(), m, )}
func (m *dbFactory) GetAdminPermissions() ([]AdminPermission, error) { if m.adminPermissions == nil { var adminPermissions []AdminPermission err := m.mongoDbFactory.Db(AdminPermission{}).Query().Where(bson.M{ "_id": m.adminID, }).ToArray(&adminPermissions) if err != nil { return nil, err }
m.adminPermissions = adminPermissions }
return m.adminPermissions, nil}
func (m *dbFactory) Uow() IUnitOfWork { uow := m.mongoDbFactory.Uow() return newUnitOfWorkRepository( uow.(IUnitOfWorkRepository), m, )}
// 创建数据库工厂func NewDbFactory( mongoDbFactory IDbFactory, adminID string,) IDbFactory { return &dbFactory{ mongoDbFactory: mongoDbFactory, adminID: adminID, }}
复制代码
结尾

对于后台管理应用, 如果权限默认开启的话, 那么当权限刚上线的那一刻所有人都没有权限, 还得花不少时间新增所有人的权限数据, 反过来则只需要添加一些需要限制人员的数据即可, 或者后续开发一个控制页面, 让权限以灵活的方式又不影响功能的使用.

其他的部分都可以参考ts的实现, 这里就不再提供代码了.

文章到此结束了, 如果有任何问题和疑问, 欢迎留言, 谢谢.

发布于: 2022 年 06 月 03 日阅读数: 6
用户头像

林逸民

关注

痛苦丢给身体 舒适留给灵魂 2018.11.13 加入

编程爱好者

评论

发布
暂无评论
[go] 后台管理数据权限控制实现 (无业务修改)_林逸民_InfoQ写作社区