mirror of
https://github.com/veops/oneterm.git
synced 2025-10-05 15:27:01 +08:00
168 lines
4.8 KiB
Go
168 lines
4.8 KiB
Go
package controller
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
"sync"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/samber/lo"
|
|
"go.uber.org/zap"
|
|
"golang.org/x/sync/errgroup"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/veops/oneterm/acl"
|
|
"github.com/veops/oneterm/conf"
|
|
mysql "github.com/veops/oneterm/db"
|
|
"github.com/veops/oneterm/logger"
|
|
"github.com/veops/oneterm/model"
|
|
)
|
|
|
|
func HandleAuthorization(currentUser *acl.Session, tx *gorm.DB, action int, old, new *model.Asset) (err error) {
|
|
ctx := context.Background()
|
|
assetId := lo.TernaryF(new == nil, func() int { return old.Id }, func() int { return new.Id })
|
|
mtx := &sync.Mutex{}
|
|
eg := &errgroup.Group{}
|
|
if action == model.ACTION_UPDATE {
|
|
if sameAuthorization(old.Authorization, new.Authorization) {
|
|
return
|
|
}
|
|
for id := range old.Authorization {
|
|
if _, ok := new.Authorization[id]; ok {
|
|
continue
|
|
}
|
|
accountId := id
|
|
eg.Go(func() (err error) {
|
|
a := &model.Authorization{}
|
|
if err = mysql.DB.
|
|
Model(a).
|
|
Select("id", "resource_id").
|
|
Where("asset_id = ? AND account_id = ?", assetId, accountId).
|
|
First(a).
|
|
Error; err != nil {
|
|
return
|
|
}
|
|
if err = acl.DeleteResource(ctx, currentUser.GetUid(), a.ResourceId); err != nil {
|
|
return
|
|
}
|
|
mtx.Lock()
|
|
defer mtx.Unlock()
|
|
err = tx.Delete(a, a.Id).Error
|
|
return
|
|
})
|
|
}
|
|
}
|
|
as := lo.TernaryF(action == model.ACTION_DELETE,
|
|
func() model.Map[int, model.Slice[int]] { return old.Authorization },
|
|
func() model.Map[int, model.Slice[int]] { return new.Authorization })
|
|
for k, v := range as {
|
|
accountId := k
|
|
curRids := lo.Uniq(v)
|
|
eg.Go(func() (err error) {
|
|
resourceId := 0
|
|
if err = mysql.DB.
|
|
Model(&model.Authorization{}).
|
|
Select("resource_id").
|
|
Where("asset_id = ? AND account_id = ?", assetId, accountId).
|
|
First(&resourceId).
|
|
Error; err != nil {
|
|
notFount := errors.Is(err, gorm.ErrRecordNotFound)
|
|
if !notFount || (notFount && action == model.ACTION_DELETE) {
|
|
return
|
|
}
|
|
if resourceId, err = acl.CreateGrantAcl(ctx, currentUser, conf.GetResourceTypeName(conf.RESOURCE_AUTHORIZATION),
|
|
fmt.Sprintf("%d-%d", assetId, accountId)); err != nil {
|
|
return
|
|
}
|
|
mtx.Lock()
|
|
if err = tx.Create(&model.Authorization{AssetId: assetId, AccountId: accountId, ResourceId: resourceId,
|
|
CreatorId: currentUser.GetUid(), UpdaterId: currentUser.GetUid()}).Error; err != nil {
|
|
return
|
|
}
|
|
mtx.Unlock()
|
|
}
|
|
switch action {
|
|
case model.ACTION_CREATE:
|
|
err = acl.BatchGrantRoleResource(ctx, currentUser.GetUid(), curRids, resourceId, []string{acl.READ})
|
|
case model.ACTION_DELETE:
|
|
err = acl.DeleteResource(ctx, currentUser.GetUid(), resourceId)
|
|
case model.ACTION_UPDATE:
|
|
var res map[string]*acl.ResourcePermissionsRespItem
|
|
res, err = acl.GetResourcePermissions(ctx, resourceId)
|
|
if err != nil {
|
|
return
|
|
}
|
|
perms := make([]*acl.Perm, 0)
|
|
for _, v := range res {
|
|
perms = append(perms, v.Perms...)
|
|
}
|
|
preRids := lo.Map(lo.Filter(perms, func(p *acl.Perm, _ int) bool { return p.Name == acl.READ }), func(p *acl.Perm, _ int) int { return p.Rid })
|
|
revokeRids := lo.Without(preRids, curRids...)
|
|
if len(revokeRids) > 0 {
|
|
if err = acl.BatchRevokeRoleResource(ctx, currentUser.GetUid(), revokeRids, resourceId, []string{acl.READ}); err != nil {
|
|
return
|
|
}
|
|
}
|
|
grantRids := lo.Without(curRids, preRids...)
|
|
if len(grantRids) > 0 {
|
|
err = acl.BatchGrantRoleResource(ctx, currentUser.GetUid(), grantRids, resourceId, []string{acl.READ})
|
|
}
|
|
return
|
|
}
|
|
return
|
|
})
|
|
}
|
|
|
|
err = eg.Wait()
|
|
|
|
return
|
|
}
|
|
|
|
func sameAuthorization(old, new model.Map[int, model.Slice[int]]) bool {
|
|
if len(old) != len(new) {
|
|
return false
|
|
}
|
|
ks := lo.Uniq(append(lo.Keys(old), lo.Keys(new)...))
|
|
for _, k := range ks {
|
|
if len(old[k]) != len(new[k]) {
|
|
return false
|
|
}
|
|
o, n := make([]int, 0, len(old[k])), make([]int, 0, len(new[k]))
|
|
copy(o, old[k])
|
|
copy(n, new[k])
|
|
sort.Ints(o)
|
|
sort.Ints(n)
|
|
if !reflect.DeepEqual(o, n) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func GetAutorizationResourceIds(ctx *gin.Context) (resourceIds []int, err error) {
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
var rs []*acl.Resource
|
|
rs, err = acl.GetRoleResources(ctx, currentUser.Acl.Rid, conf.RESOURCE_AUTHORIZATION)
|
|
if err != nil {
|
|
return
|
|
}
|
|
resourceIds = lo.Map(rs, func(r *acl.Resource, _ int) int { return r.ResourceId })
|
|
|
|
return
|
|
}
|
|
|
|
func HasAuthorization(ctx *gin.Context) (ok bool) {
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
rs, err := acl.GetRoleResources(ctx, currentUser.Acl.Rid, conf.RESOURCE_AUTHORIZATION)
|
|
if err != nil {
|
|
logger.L().Error("check authorization failed", zap.Error(err))
|
|
return
|
|
}
|
|
k := fmt.Sprintf("%d-%d", ctx.Param("asset_id"), ctx.Param("account_id"))
|
|
_, ok = lo.Find(rs, func(r *acl.Resource) bool { return k == r.Name })
|
|
return
|
|
}
|