缺少事务可能出现数据不一致风险 (#1575)

Co-authored-by: zongqiang <zongq@rp-pet.cn>
This commit is contained in:
ZongQiang
2023-11-18 22:20:26 +08:00
committed by GitHub
co-authored by zongqiang
parent aa6ca95f13
commit 5ef0e43312
4 changed files with 165 additions and 56 deletions
+87 -32
View File
@@ -2,6 +2,8 @@ package system
import (
"errors"
"github.com/casbin/casbin/v2"
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
"strconv"
"github.com/flipped-aurora/gin-vue-admin/server/global"
@@ -24,12 +26,56 @@ type AuthorityService struct{}
var AuthorityServiceApp = new(AuthorityService)
func (authorityService *AuthorityService) CreateAuthority(auth system.SysAuthority) (authority system.SysAuthority, err error) {
var authorityBox system.SysAuthority
if !errors.Is(global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&authorityBox).Error, gorm.ErrRecordNotFound) {
if err = global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&system.SysAuthority{}).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
return auth, ErrRoleExistence
}
err = global.GVA_DB.Create(&auth).Error
return auth, err
e := global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if err = tx.Create(&auth).Error; err != nil {
return err
}
auth.SysBaseMenus = systemReq.DefaultMenu()
if err = tx.Model(&auth).Association("SysBaseMenus").Replace(&auth.SysBaseMenus); err != nil {
return err
}
casbinInfos := systemReq.DefaultCasbin()
authorityId := strconv.Itoa(int(auth.AuthorityId))
rules := [][]string{}
//做权限去重处理
deduplicateMap := make(map[string]bool)
for _, v := range casbinInfos {
key := authorityId + v.Path + v.Method
if _, ok := deduplicateMap[key]; !ok {
deduplicateMap[key] = true
rules = append(rules, []string{authorityId, v.Path, v.Method})
}
}
var sce *casbin.SyncedEnforcer
if sce, err = CasbinServiceApp.CasbinWithDB(tx); err != nil {
return err
}
var success bool
if _, err = sce.RemoveFilteredPolicy(0, authorityId); err != nil {
// errors.New("从当前策略中删除授权规则失败!")
return err
}
if success, err = sce.AddPolicies(rules); err != nil || !success {
if err != nil {
return err
}
return errors.New("存在相同api,添加失败,请联系管理员!")
}
return nil
})
return auth, e
}
//@author: [piexlmax](https://github.com/piexlmax)
@@ -101,7 +147,7 @@ func (authorityService *AuthorityService) UpdateAuthority(auth system.SysAuthori
//@param: auth *model.SysAuthority
//@return: err error
func (authorityService *AuthorityService) DeleteAuthority(auth *system.SysAuthority) (err error) {
func (authorityService *AuthorityService) DeleteAuthority(auth *system.SysAuthority) error {
if errors.Is(global.GVA_DB.Debug().Preload("Users").First(&auth).Error, gorm.ErrRecordNotFound) {
return errors.New("该角色不存在")
}
@@ -114,35 +160,44 @@ func (authorityService *AuthorityService) DeleteAuthority(auth *system.SysAuthor
if !errors.Is(global.GVA_DB.Where("parent_id = ?", auth.AuthorityId).First(&system.SysAuthority{}).Error, gorm.ErrRecordNotFound) {
return errors.New("此角色存在子角色不允许删除")
}
db := global.GVA_DB.Preload("SysBaseMenus").Preload("DataAuthorityId").Where("authority_id = ?", auth.AuthorityId).First(auth)
err = db.Unscoped().Delete(auth).Error
if err != nil {
return
}
if len(auth.SysBaseMenus) > 0 {
err = global.GVA_DB.Model(auth).Association("SysBaseMenus").Delete(auth.SysBaseMenus)
if err != nil {
return
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
var err error
if err = tx.Preload("SysBaseMenus").Preload("DataAuthorityId").Where("authority_id = ?", auth.AuthorityId).First(auth).Unscoped().Delete(auth).Error; err != nil {
return err
}
// err = db.Association("SysBaseMenus").Delete(&auth)
}
if len(auth.DataAuthorityId) > 0 {
err = global.GVA_DB.Model(auth).Association("DataAuthorityId").Delete(auth.DataAuthorityId)
if err != nil {
return
if len(auth.SysBaseMenus) > 0 {
if err = tx.Model(auth).Association("SysBaseMenus").Delete(auth.SysBaseMenus); err != nil {
return err
}
// err = db.Association("SysBaseMenus").Delete(&auth)
}
}
err = global.GVA_DB.Delete(&[]system.SysUserAuthority{}, "sys_authority_authority_id = ?", auth.AuthorityId).Error
if err != nil {
return
}
err = global.GVA_DB.Delete(&[]system.SysAuthorityBtn{}, "authority_id = ?", auth.AuthorityId).Error
if err != nil {
return
}
authorityId := strconv.Itoa(int(auth.AuthorityId))
CasbinServiceApp.ClearCasbin(0, authorityId)
return err
if len(auth.DataAuthorityId) > 0 {
if err = tx.Model(auth).Association("DataAuthorityId").Delete(auth.DataAuthorityId); err != nil {
return err
}
}
if err = tx.Delete(&system.SysUserAuthority{}, "sys_authority_authority_id = ?", auth.AuthorityId).Error; err != nil {
return err
}
if err = tx.Where("authority_id = ?", auth.AuthorityId).Delete(&[]system.SysAuthorityBtn{}).Error; err != nil {
return err
}
authorityId := strconv.Itoa(int(auth.AuthorityId))
var sce *casbin.SyncedEnforcer
if sce, err = CasbinServiceApp.CasbinWithDB(tx); err != nil {
return err
}
if _, err = sce.RemoveFilteredPolicy(0, authorityId); err != nil {
return err
}
return nil
})
}
//@author: [piexlmax](https://github.com/piexlmax)
+46
View File
@@ -2,6 +2,7 @@ package system
import (
"errors"
"gorm.io/gorm"
"strconv"
"sync"
@@ -139,3 +140,48 @@ func (casbinService *CasbinService) Casbin() *casbin.SyncedCachedEnforcer {
})
return syncedCachedEnforcer
}
func (casbinService *CasbinService) CasbinWithDB(db *gorm.DB) (*casbin.SyncedEnforcer, error) {
var a *gormadapter.Adapter
var m model.Model
var s *casbin.SyncedEnforcer
var err error
var text = `
[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 = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act
`
if a, err = gormadapter.NewAdapterByDB(db); err != nil {
zap.L().Error("适配数据库失败请检查casbin表是否为InnoDB引擎!", zap.Error(err))
return nil, err
}
if m, err = model.NewModelFromString(text); err != nil {
zap.L().Error("字符串加载模型失败!", zap.Error(err))
return nil, err
}
if s, err = casbin.NewSyncedEnforcer(m, a); err != nil {
zap.L().Error("通过文件或 DB 创建执行器失败!", zap.Error(err))
return nil, err
}
if err = s.LoadPolicy(); err != nil {
zap.L().Error("从持久层中加载policy规则失败!", zap.Error(err))
return nil, err
}
return s, nil
}
+9 -7
View File
@@ -148,13 +148,15 @@ func (userService *UserService) SetUserAuthorities(id uint, authorityIds []uint)
//@return: err error
func (userService *UserService) DeleteUser(id int) (err error) {
var user system.SysUser
err = global.GVA_DB.Where("id = ?", id).Delete(&user).Error
if err != nil {
return err
}
err = global.GVA_DB.Delete(&[]system.SysUserAuthority{}, "sys_user_id = ?", id).Error
return err
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("id = ?", id).Delete(&system.SysUser{}).Error; err != nil {
return err
}
if err := tx.Delete(&[]system.SysUserAuthority{}, "sys_user_id = ?", id).Error; err != nil {
return err
}
return nil
})
}
//@author: [piexlmax](https://github.com/piexlmax)