package user import ( "context" "time" "perms-system-server/internal/consts" authHelper "perms-system-server/internal/logic/auth" "perms-system-server/internal/middleware" "perms-system-server/internal/model/userrole" "perms-system-server/internal/response" "perms-system-server/internal/svc" "perms-system-server/internal/types" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/sqlx" ) type BindRolesLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewBindRolesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BindRolesLogic { return &BindRolesLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } // BindRoles 绑定用户角色。对指定用户在当前产品下做角色全量覆盖(diff 后批量新增/删除),支持权限级别校验防止越权分配。 func (l *BindRolesLogic) BindRoles(req *types.BindRolesReq) error { caller := middleware.GetUserDetails(l.ctx) if caller == nil { return response.ErrUnauthorized("未登录") } targetUser, err := l.svcCtx.SysUserModel.FindOne(l.ctx, req.UserId) if err != nil { return response.ErrNotFound("用户不存在") } productCode := middleware.GetProductCode(l.ctx) if err := authHelper.CheckManageAccess(l.ctx, l.svcCtx, req.UserId, productCode, authHelper.WithPrefetchedTarget(targetUser)); err != nil { return err } member, err := l.svcCtx.SysProductMemberModel.FindOneByProductCodeUserId(l.ctx, productCode, req.UserId) if err != nil { return response.ErrBadRequest("目标用户不是当前产品的成员") } if member.Status != consts.StatusEnabled { return response.ErrBadRequest("目标用户的成员资格已被禁用") } roleIds := req.RoleIds if len(roleIds) > 0 { seen := make(map[int64]bool, len(roleIds)) uniqueIds := make([]int64, 0, len(roleIds)) for _, id := range roleIds { if !seen[id] { seen[id] = true uniqueIds = append(uniqueIds, id) } } roleIds = uniqueIds } if len(roleIds) > 0 { roles, err := l.svcCtx.SysRoleModel.FindByIds(l.ctx, roleIds) if err != nil { return err } if int64(len(roles)) != int64(len(roleIds)) { return response.ErrBadRequest("包含无效的角色ID") } for _, r := range roles { if r.ProductCode != productCode { return response.ErrBadRequest("不能绑定其他产品的角色") } if r.Status != consts.StatusEnabled { return response.ErrBadRequest("不能绑定已禁用的角色") } if err := authHelper.GuardRoleLevelAssignable(l.ctx, l.svcCtx, caller, r.PermsLevel); err != nil { return err } } } existingRoleIds, err := l.svcCtx.SysUserRoleModel.FindRoleIdsByUserIdForProduct(l.ctx, req.UserId, productCode) if err != nil { return err } existingSet := make(map[int64]bool, len(existingRoleIds)) for _, id := range existingRoleIds { existingSet[id] = true } newSet := make(map[int64]bool, len(roleIds)) for _, id := range roleIds { newSet[id] = true } var toAdd []int64 for _, id := range roleIds { if !existingSet[id] { toAdd = append(toAdd, id) } } var toRemove []int64 for _, id := range existingRoleIds { if !newSet[id] { toRemove = append(toRemove, id) } } if len(toAdd) == 0 && len(toRemove) == 0 { l.svcCtx.UserDetailsLoader.Clean(l.ctx, req.UserId) return nil } if err := l.svcCtx.SysUserRoleModel.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error { if err := l.svcCtx.SysUserRoleModel.DeleteByUserIdAndRoleIdsTx(ctx, session, req.UserId, toRemove); err != nil { return err } if len(toAdd) > 0 { now := time.Now().Unix() data := make([]*userrole.SysUserRole, 0, len(toAdd)) for _, roleId := range toAdd { data = append(data, &userrole.SysUserRole{ UserId: req.UserId, RoleId: roleId, CreateTime: now, UpdateTime: now, }) } return l.svcCtx.SysUserRoleModel.BatchInsertWithTx(ctx, session, data) } return nil }); err != nil { return err } l.svcCtx.UserDetailsLoader.Clean(l.ctx, req.UserId) return nil }