feat(user): enhance path management and role handling (#9249)

- Add `GetUsersByRole` function for fetching users by role.
- Introduce `GetAllBasePathsFromRoles` to aggregate paths from roles.
- Refine path handling in `pkg/utils/path.go` for normalization.
- Comment out base path prefix updates to simplify role operations.
main beta
千石 2025-08-06 16:31:36 +08:00 committed by GitHub
parent 85fe4e5bb3
commit 6b2d81eede
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 89 additions and 40 deletions

View File

@ -149,9 +149,21 @@ func (u *User) JoinPath(reqPath string) (string, error) {
if err != nil {
return "", err
}
if u.CheckPathLimit() && !utils.IsSubPath(u.BasePath, path) {
return "", errs.PermissionDenied
if u.CheckPathLimit() {
basePaths := GetAllBasePathsFromRoles(u)
match := false
for _, base := range basePaths {
if utils.IsSubPath(base, path) {
match = true
break
}
}
if !match {
return "", errs.PermissionDenied
}
}
return path, nil
}
@ -193,3 +205,22 @@ func (u *User) WebAuthnCredentials() []webauthn.Credential {
func (u *User) WebAuthnIcon() string {
return "https://alistgo.com/logo.svg"
}
// GetAllBasePathsFromRoles returns all permission paths from user's roles
func GetAllBasePathsFromRoles(u *User) []string {
basePaths := make([]string, 0)
seen := make(map[string]struct{})
for _, role := range u.RolesDetail {
for _, entry := range role.PermissionScopes {
if entry.Path == "" {
continue
}
if _, ok := seen[entry.Path]; !ok {
basePaths = append(basePaths, entry.Path)
seen[entry.Path] = struct{}{}
}
}
}
return basePaths
}

View File

@ -2,7 +2,6 @@ package op
import (
"fmt"
"github.com/pkg/errors"
"time"
"github.com/Xhofe/go-cache"
@ -106,26 +105,26 @@ func UpdateRole(r *model.Role) error {
for i := range r.PermissionScopes {
r.PermissionScopes[i].Path = utils.FixAndCleanPath(r.PermissionScopes[i].Path)
}
if len(old.PermissionScopes) > 0 && len(r.PermissionScopes) > 0 &&
old.PermissionScopes[0].Path != r.PermissionScopes[0].Path {
oldPath := old.PermissionScopes[0].Path
newPath := r.PermissionScopes[0].Path
users, err := db.GetUsersByRole(int(r.ID))
if err != nil {
return errors.WithMessage(err, "failed to get users by role")
}
modifiedUsernames, err := db.UpdateUserBasePathPrefix(oldPath, newPath, users)
if err != nil {
return errors.WithMessage(err, "failed to update user base path when role updated")
}
for _, name := range modifiedUsernames {
userCache.Del(name)
}
}
//if len(old.PermissionScopes) > 0 && len(r.PermissionScopes) > 0 &&
// old.PermissionScopes[0].Path != r.PermissionScopes[0].Path {
//
// oldPath := old.PermissionScopes[0].Path
// newPath := r.PermissionScopes[0].Path
//
// users, err := db.GetUsersByRole(int(r.ID))
// if err != nil {
// return errors.WithMessage(err, "failed to get users by role")
// }
//
// modifiedUsernames, err := db.UpdateUserBasePathPrefix(oldPath, newPath, users)
// if err != nil {
// return errors.WithMessage(err, "failed to update user base path when role updated")
// }
//
// for _, name := range modifiedUsernames {
// userCache.Del(name)
// }
//}
roleCache.Del(fmt.Sprint(r.ID))
roleCache.Del(r.Name)
return db.UpdateRole(r)

View File

@ -232,12 +232,20 @@ func UpdateStorage(ctx context.Context, storage model.Storage) error {
roleCache.Del(fmt.Sprint(id))
}
modifiedUsernames, err := db.UpdateUserBasePathPrefix(oldStorage.MountPath, storage.MountPath)
if err != nil {
return errors.WithMessage(err, "failed to update user base path")
}
for _, name := range modifiedUsernames {
userCache.Del(name)
//modifiedUsernames, err := db.UpdateUserBasePathPrefix(oldStorage.MountPath, storage.MountPath)
//if err != nil {
// return errors.WithMessage(err, "failed to update user base path")
//}
for _, id := range modifiedRoleIDs {
roleCache.Del(fmt.Sprint(id))
users, err := db.GetUsersByRole(int(id))
if err != nil {
return errors.WithMessage(err, "failed to get users by role")
}
for _, user := range users {
userCache.Del(user.Username)
}
}
}
if err != nil {

View File

@ -50,6 +50,10 @@ func GetUserByRole(role int) (*model.User, error) {
return db.GetUserByRole(role)
}
func GetUsersByRole(role int) ([]model.User, error) {
return db.GetUsersByRole(role)
}
func GetUserByName(username string) (*model.User, error) {
if username == "" {
return nil, errs.EmptyUsername
@ -124,17 +128,17 @@ func UpdateUser(u *model.User) error {
}
userCache.Del(old.Username)
u.BasePath = utils.FixAndCleanPath(u.BasePath)
if len(u.Role) > 0 {
roles, err := GetRolesByUserID(u.ID)
if err == nil {
for _, role := range roles {
if len(role.PermissionScopes) > 0 {
u.BasePath = utils.FixAndCleanPath(role.PermissionScopes[0].Path)
break
}
}
}
}
//if len(u.Role) > 0 {
// roles, err := GetRolesByUserID(u.ID)
// if err == nil {
// for _, role := range roles {
// if len(role.PermissionScopes) > 0 {
// u.BasePath = utils.FixAndCleanPath(role.PermissionScopes[0].Path)
// break
// }
// }
// }
//}
return db.UpdateUser(u)
}

View File

@ -88,6 +88,13 @@ func JoinBasePath(basePath, reqPath string) (string, error) {
strings.Contains(reqPath, "/../") {
return "", errs.RelativePath
}
reqPath = FixAndCleanPath(reqPath)
if strings.HasPrefix(reqPath, "/") {
return reqPath, nil
}
return stdpath.Join(FixAndCleanPath(basePath), FixAndCleanPath(reqPath)), nil
}