package auth import ( "context" "math" "strings" "perms-system-server/internal/consts" "perms-system-server/internal/loaders" "perms-system-server/internal/middleware" "perms-system-server/internal/response" "perms-system-server/internal/svc" ) func memberTypePriority(memberType string) int { switch memberType { case consts.MemberTypeSuperAdmin: return 0 case consts.MemberTypeAdmin: return 1 case consts.MemberTypeDeveloper: return 2 case consts.MemberTypeMember: return 3 default: return math.MaxInt32 } } // CheckManageAccess 检查当前操作者是否有权管理目标用户。 // 规则: // 1. SUPER_ADMIN 完全豁免 // 2. 操作自己豁免 // 3. 部门检查:目标用户须在操作者本部门或下级子部门(ADMIN 豁免) // 4. 权限级别检查:操作者的级别必须严格高于目标用户 // - 先比 memberType 优先级(SUPER_ADMIN > ADMIN > DEVELOPER > MEMBER) // - 同 memberType 时比 permsLevel(数值越小权限越高) func CheckManageAccess(ctx context.Context, svcCtx *svc.ServiceContext, targetUserId int64, productCode string) error { caller := middleware.GetUserDetails(ctx) if caller == nil { return response.ErrUnauthorized("未登录") } if caller.IsSuperAdmin { return nil } if caller.UserId == targetUserId { return nil } if err := checkDeptHierarchy(ctx, svcCtx, caller, targetUserId); err != nil { return err } return checkPermLevel(ctx, svcCtx, caller, targetUserId, productCode) } // CheckMemberTypeAssignment 检查操作者是否有权分配指定的 memberType。 func CheckMemberTypeAssignment(ctx context.Context, assignedType string) error { caller := middleware.GetUserDetails(ctx) if caller == nil { return response.ErrUnauthorized("未登录") } if caller.IsSuperAdmin { return nil } if memberTypePriority(caller.MemberType) >= memberTypePriority(assignedType) { return response.ErrForbidden("无权分配该成员类型,不能分配与自己同级或更高级别的类型") } return nil } // RequireSuperAdmin 要求当前操作者必须是超级管理员。 func RequireSuperAdmin(ctx context.Context) error { caller := middleware.GetUserDetails(ctx) if caller == nil { return response.ErrUnauthorized("未登录") } if !caller.IsSuperAdmin { return response.ErrForbidden("仅超级管理员可执行此操作") } return nil } // RequireProductAdminFor 要求当前操作者是超级管理员或指定产品的管理员。 func RequireProductAdminFor(ctx context.Context, targetProductCode string) error { caller := middleware.GetUserDetails(ctx) if caller == nil { return response.ErrUnauthorized("未登录") } if caller.IsSuperAdmin { return nil } if caller.MemberType == consts.MemberTypeAdmin && caller.ProductCode == targetProductCode { return nil } return response.ErrForbidden("仅超级管理员或该产品的管理员可执行此操作") } // ValidateStatusChange 校验状态变更的合法性(不允许自改状态、不允许冻结超管)。 // UpdateUser 和 UpdateUserStatus 共用此函数以确保校验逻辑一致。 func ValidateStatusChange(ctx context.Context, svcCtx *svc.ServiceContext, callerId, targetUserId int64) error { if callerId == targetUserId { return response.ErrBadRequest("不能修改自己的状态") } target, err := svcCtx.SysUserModel.FindOne(ctx, targetUserId) if err != nil { return response.ErrNotFound("用户不存在") } if target.IsSuperAdmin == consts.IsSuperAdminYes { return response.ErrForbidden("不能修改超级管理员的状态") } return nil } func checkDeptHierarchy(ctx context.Context, svcCtx *svc.ServiceContext, caller *loaders.UserDetails, targetUserId int64) error { if caller.MemberType == consts.MemberTypeAdmin { return nil } if caller.DeptId == 0 { return response.ErrForbidden("您未归属任何部门,无权管理其他用户") } if caller.DeptPath == "" { return response.ErrForbidden("您的部门信息异常,无法执行此操作") } target, err := svcCtx.SysUserModel.FindOne(ctx, targetUserId) if err != nil { return response.ErrNotFound("目标用户不存在") } if target.DeptId == 0 { return response.ErrForbidden("目标用户未归属部门,仅超管或产品管理员可管理") } targetDept, err := svcCtx.SysDeptModel.FindOne(ctx, target.DeptId) if err != nil { return response.ErrForbidden("无权操作") } if !strings.HasPrefix(targetDept.Path, caller.DeptPath) { return response.ErrForbidden("无权管理其他部门的用户") } return nil } func checkPermLevel(ctx context.Context, svcCtx *svc.ServiceContext, caller *loaders.UserDetails, targetUserId int64, productCode string) error { if productCode == "" { return response.ErrBadRequest("缺少产品上下文,无法进行权限级别判定") } targetMember, err := svcCtx.SysProductMemberModel.FindOneByProductCodeUserId(ctx, productCode, targetUserId) if err != nil { return response.ErrForbidden("目标用户不是当前产品的成员,无法执行管理操作") } targetMemberType := targetMember.MemberType callerPri := memberTypePriority(caller.MemberType) targetPri := memberTypePriority(targetMemberType) if callerPri > targetPri { return response.ErrForbidden("无权管理权限级别高于您的用户") } if callerPri < targetPri { return nil } // memberType 相同,比较 permsLevel targetLevel, err := svcCtx.SysRoleModel.FindMinPermsLevelByUserIdAndProductCode(ctx, targetUserId, productCode) if err != nil { targetLevel = math.MaxInt64 } if caller.MinPermsLevel >= targetLevel { return response.ErrForbidden("无权管理权限级别高于或等于您的用户") } return nil }