优化
This commit is contained in:
+63
-29
@@ -3,8 +3,6 @@ package data
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"kra/internal/biz"
|
||||
|
||||
@@ -89,9 +87,11 @@ func (r *authorityAccessRepo) CreateAuthority(ctx context.Context, value *biz.Au
|
||||
if value.DefaultRouter == "" {
|
||||
value.DefaultRouter = "dashboard"
|
||||
}
|
||||
if err := tx.Create(&authorityPO{AuthorityID: value.AuthorityID, AuthorityName: value.AuthorityName, ParentID: value.ParentID, DataScope: value.DataScope, DefaultRouter: value.DefaultRouter}).Error; err != nil {
|
||||
po := authorityPO{AuthorityID: value.AuthorityID, AuthorityName: value.AuthorityName, ParentID: value.ParentID, DataScope: value.DataScope, DefaultRouter: value.DefaultRouter}
|
||||
if err := tx.Create(&po).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
value.CreatedAt, value.UpdatedAt = po.CreatedAt, po.UpdatedAt
|
||||
var dashboard menuPO
|
||||
if err := tx.Where("name = ?", "dashboard").First(&dashboard).Error; err == nil {
|
||||
if err = tx.Create(&authorityMenuPO{SysAuthorityAuthorityID: value.AuthorityID, SysBaseMenuID: dashboard.ID}).Error; err != nil {
|
||||
@@ -99,13 +99,12 @@ func (r *authorityAccessRepo) CreateAuthority(ctx context.Context, value *biz.Au
|
||||
}
|
||||
}
|
||||
defaults := []struct{ path, method string }{{"/menu/getMenu", "POST"}, {"/jwt/jsonInBlacklist", "POST"}, {"/base/login", "POST"}, {"/user/changePassword", "POST"}, {"/user/setUserAuthority", "POST"}, {"/user/getUserInfo", "GET"}, {"/user/setSelfInfo", "PUT"}, {"/fileUploadAndDownload/upload", "POST"}, {"/sysDictionary/findSysDictionary", "GET"}}
|
||||
rules := make([]casbinRulePO, 0, len(defaults))
|
||||
for _, item := range defaults {
|
||||
var api apiPO
|
||||
if err := tx.Where("path = ? AND method = ?", item.path, item.method).First(&api).Error; err == nil {
|
||||
if err = tx.Create(&authorityAPIPO{AuthorityID: value.AuthorityID, APIID: api.ID}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
rules = append(rules, newPolicyRule(value.AuthorityID, item.path, item.method))
|
||||
}
|
||||
if err := tx.Create(&rules).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -114,13 +113,18 @@ func (r *authorityAccessRepo) CopyAuthority(ctx context.Context, sourceID uint,
|
||||
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
config := r.data.runtime.Admin()
|
||||
actor, hasActor := biz.ActorFromContext(ctx)
|
||||
strict := hasActor && actor.AuthorityID != 888 && config != nil && config.System != nil && config.System.UseStrictAuth
|
||||
// Strict-authority checks apply to every actor. A root actor is
|
||||
// allowed to create/copy a role directly below itself; non-root actors
|
||||
// may target themselves' descendants. Do not special-case 888 here:
|
||||
// the configured strict-auth switch is the source of truth.
|
||||
strict := hasActor && config != nil && config.System != nil && config.System.UseStrictAuth
|
||||
if strict {
|
||||
allowed, err := r.strictAuthorityIDs(ctx, actor.AuthorityID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value.ParentID == nil || !allowed[*value.ParentID] {
|
||||
parentAllowed := value.ParentID != nil && (allowed[*value.ParentID] || *value.ParentID == actor.AuthorityID)
|
||||
if !parentAllowed {
|
||||
return errors.New("严格角色模式下只能在自己的角色树中复制角色")
|
||||
}
|
||||
}
|
||||
@@ -131,9 +135,11 @@ func (r *authorityAccessRepo) CopyAuthority(ctx context.Context, sourceID uint,
|
||||
if count != 0 {
|
||||
return errors.New("存在相同角色id")
|
||||
}
|
||||
if err := tx.Create(&authorityPO{AuthorityID: value.AuthorityID, AuthorityName: value.AuthorityName, ParentID: value.ParentID, DataScope: value.DataScope, DefaultRouter: value.DefaultRouter}).Error; err != nil {
|
||||
po := authorityPO{AuthorityID: value.AuthorityID, AuthorityName: value.AuthorityName, ParentID: value.ParentID, DataScope: value.DataScope, DefaultRouter: value.DefaultRouter}
|
||||
if err := tx.Create(&po).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
value.CreatedAt, value.UpdatedAt = po.CreatedAt, po.UpdatedAt
|
||||
copyLinks := func(table string, destination any, columns map[string]any) error {
|
||||
return tx.Table(table).Where(columns).Find(destination).Error
|
||||
}
|
||||
@@ -149,24 +155,31 @@ func (r *authorityAccessRepo) CopyAuthority(ctx context.Context, sourceID uint,
|
||||
return err
|
||||
}
|
||||
}
|
||||
var apis []authorityAPIPO
|
||||
if err := copyLinks("sys_authority_apis", &apis, map[string]any{"authority_id": sourceID}); err != nil {
|
||||
apis, err := policyRowsForAuthority(tx, sourceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range apis {
|
||||
copiedRules := make([]casbinRulePO, 0, len(apis))
|
||||
seenPolicies := make(map[string]struct{}, len(apis))
|
||||
for _, api := range apis {
|
||||
if strict {
|
||||
var allowedCount int64
|
||||
if err := tx.Model(&authorityAPIPO{}).Where("authority_id = ? AND api_id = ?", actor.AuthorityID, apis[i].APIID).Count(&allowedCount).Error; err != nil {
|
||||
allowed, err := policyExists(tx, actor.AuthorityID, api.V1, api.V2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if allowedCount == 0 {
|
||||
if !allowed {
|
||||
return errors.New("严格角色模式下不能复制当前角色未拥有的 API")
|
||||
}
|
||||
}
|
||||
apis[i].AuthorityID = value.AuthorityID
|
||||
key := api.V1 + "\x00" + api.V2
|
||||
if _, ok := seenPolicies[key]; ok {
|
||||
continue
|
||||
}
|
||||
seenPolicies[key] = struct{}{}
|
||||
copiedRules = append(copiedRules, newPolicyRule(value.AuthorityID, api.V1, api.V2))
|
||||
}
|
||||
if len(apis) > 0 {
|
||||
if err := tx.Create(&apis).Error; err != nil {
|
||||
if len(copiedRules) > 0 {
|
||||
if err := tx.Create(&copiedRules).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -225,13 +238,18 @@ func (r *authorityAccessRepo) DeleteAuthority(ctx context.Context, id uint) erro
|
||||
if err := tx.Where("sys_authority_authority_id = ?", id).Delete(&authorityMenuPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deletePoliciesForAuthority(tx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("authority_id = ?", id).Delete(&authorityAPIPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("authority_id = ?", id).Delete(&authorityButtonPO{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Delete(&authorityPO{}, "authority_id = ?", id).Error
|
||||
// The compatible delete removes the role row permanently with Unscoped().Delete,
|
||||
// so reusing an authority ID after deletion behaves the same way.
|
||||
return tx.Unscoped().Delete(&authorityPO{}, "authority_id = ?", id).Error
|
||||
})
|
||||
}
|
||||
func (r *authorityAccessRepo) ListAuthorities(ctx context.Context) ([]*biz.Authority, error) {
|
||||
@@ -359,19 +377,35 @@ func (r *authorityAccessRepo) ResolveDataScope(ctx context.Context, authorityID,
|
||||
ids = append(ids, id)
|
||||
}
|
||||
if identity.Scope == 2 && len(ids) > 0 {
|
||||
// Match the administration subtree-union semantics: derive the visible set from
|
||||
// parent_id edges at read time, rather than trusting the denormalized
|
||||
// ancestors string (which may be stale after a department move).
|
||||
var departments []departmentPO
|
||||
_ = r.data.gormDB.WithContext(ctx).Find(&departments).Error
|
||||
_ = r.data.gormDB.WithContext(ctx).Select("id", "parent_id").Find(&departments).Error
|
||||
children := make(map[uint][]uint, len(departments))
|
||||
for _, department := range departments {
|
||||
for _, part := range strings.Split(department.Ancestors, ",") {
|
||||
value, _ := strconv.ParseUint(part, 10, 64)
|
||||
if selected[uint(value)] {
|
||||
selected[department.ID] = true
|
||||
break
|
||||
children[department.ParentID] = append(children[department.ParentID], department.ID)
|
||||
}
|
||||
queue := make([]uint, 0, len(selected))
|
||||
for id := range selected {
|
||||
queue = append(queue, id)
|
||||
}
|
||||
visited := make(map[uint]struct{}, len(selected))
|
||||
for len(queue) > 0 {
|
||||
current := queue[0]
|
||||
queue = queue[1:]
|
||||
if _, ok := visited[current]; ok {
|
||||
continue
|
||||
}
|
||||
visited[current] = struct{}{}
|
||||
for _, child := range children[current] {
|
||||
if _, ok := visited[child]; !ok {
|
||||
queue = append(queue, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
ids = ids[:0]
|
||||
for id := range selected {
|
||||
for id := range visited {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
} else if identity.Scope == 5 {
|
||||
|
||||
Reference in New Issue
Block a user