From 45a4dde03426a24991ec72923a6625ee3abf3c88 Mon Sep 17 00:00:00 2001 From: XingQue Date: Mon, 6 Jul 2026 19:00:18 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=88=87=E6=8D=A2=E4=BF=B1=E4=B9=90?= =?UTF-8?q?=E9=83=A8=E4=BB=85=E7=AE=97=E6=9C=AC=E4=BF=B1=E4=B9=90=E9=83=A8?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90=EF=BC=8C=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E6=9D=83=E9=99=90=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- backend/utils.py | 50 ++++++++++++++++-------------------- jituan/services/club_rbac.py | 45 ++++++++++++++++++++++---------- jituan/services/kefu_menu.py | 4 +-- users/views/kefu_orders.py | 12 ++------- 4 files changed, 57 insertions(+), 54 deletions(-) diff --git a/backend/utils.py b/backend/utils.py index 5a76d26..750a77c 100644 --- a/backend/utils.py +++ b/backend/utils.py @@ -170,11 +170,10 @@ def verify_kefu_permission(request, username_from_frontend=None): 'msg': '身份错误,无权操作其他账号,相关操作已记录' }, status=403) - # ---------- 4. 获取用户的所有权限 ---------- - # 使用 gvsdsdk RBAC 表(UserRole → RolePermission → Permission) + # ---------- 4. 获取用户的所有权限(与菜单 menu-access 同一套算法) ---------- from jituan.constants import CLUB_ID_DEFAULT, DATA_SCOPE_SINGLE from jituan.services.admin_context import resolve_admin_effective_club, get_allowed_club_ids, is_system_super_admin - from jituan.services.club_rbac import filter_role_uuids_for_club_scope + from jituan.services.club_rbac import resolve_effective_permission_codes eff_club = getattr(request, 'club_id', None) or CLUB_ID_DEFAULT eff_scope = getattr(request, 'club_scope', None) or DATA_SCOPE_SINGLE @@ -188,27 +187,27 @@ def verify_kefu_permission(request, username_from_frontend=None): allowed_club_ids = list(get_allowed_club_ids(current_user)) try: - user_uuid = current_user.UserUUID - role_uuids = list(SdkUserRole.objects.filter( - UserUUID=user_uuid - ).values_list('RoleUUID', flat=True)) - - if role_uuids and not is_system_super_admin(current_user): - role_uuids = filter_role_uuids_for_club_scope( - role_uuids, eff_club, eff_scope, allowed_club_ids, - ) - - if role_uuids: - perm_uuids = list(SdkRolePermission.objects.filter( - RoleUUID__in=role_uuids - ).values_list('PermUUID', flat=True)) - - permissions = list(SdkPermission.objects.filter( - PermUUID__in=perm_uuids, - PermStatus=1 - ).values_list('PermCode', flat=True).distinct()) + if is_system_super_admin(current_user): + user_uuid = current_user.UserUUID + role_uuids = list(SdkUserRole.objects.filter( + UserUUID=user_uuid + ).values_list('RoleUUID', flat=True)) + if role_uuids: + perm_uuids = list(SdkRolePermission.objects.filter( + RoleUUID__in=role_uuids + ).values_list('PermUUID', flat=True)) + permissions = list(SdkPermission.objects.filter( + PermUUID__in=perm_uuids, PermStatus=1 + ).values_list('PermCode', flat=True).distinct()) + else: + permissions = [] + legacy_codes, _ = _legacy_backend_role_permissions(current_user.Phone) + if legacy_codes: + permissions = list(set(list(permissions) + legacy_codes)) else: - permissions = [] + permissions = resolve_effective_permission_codes( + current_user, eff_club, eff_scope, allowed_club_ids, + ) except Exception as e: logger.warning( 'verify_kefu_permission failed: UserUUID=%s Phone=%s err=%s', @@ -219,11 +218,6 @@ def verify_kefu_permission(request, username_from_frontend=None): ) permissions = [] - # 旧权限表(user_role 按手机号):仅在没有 gvsdsdk 角色绑定时兜底,避免污染多俱乐部权限 - legacy_codes, _ = _legacy_backend_role_permissions(current_user.Phone) - if legacy_codes and not role_uuids: - permissions = list(set(list(permissions) + legacy_codes)) - # 仅系统级超管自动拥有全部功能权限;俱乐部 000001 只解锁超管页,不展开全部菜单 if is_system_super_admin(current_user): if '000001' not in permissions: diff --git a/jituan/services/club_rbac.py b/jituan/services/club_rbac.py index 70dacff..9d681bb 100644 --- a/jituan/services/club_rbac.py +++ b/jituan/services/club_rbac.py @@ -135,34 +135,44 @@ def resolve_roles_for_binding(role_names, club_id=None): def filter_role_uuids_for_club_scope(role_uuids, club_id, scope, allowed_club_ids=None): """ 按当前俱乐部上下文过滤 UserRole 绑定的 RoleUUID。 - SINGLE_CLUB:本俱乐部角色 + 全局角色(ClubID 为空)。 - ALL_CLUBS:全局角色 + 各已授权俱乐部的角色(并集)。 + SINGLE_CLUB:仅本俱乐部角色(Role.ClubID=当前俱乐部),不含其他俱乐部/全局。 + ALL_CLUBS:已授权各俱乐部角色 + 全局角色(club_id 为空)。 """ if not role_uuids: return [] - qs = Role.objects.filter(RoleUUID__in=role_uuids, RoleStatus=1) + wanted = {role_uuid_bytes(u) for u in role_uuids} + if scope == DATA_SCOPE_ALL: - club_ids = [c for c in (allowed_club_ids or []) if c] - if club_ids: - return list( - qs.filter(Q(ClubID='') | Q(ClubID__in=club_ids)).values_list('RoleUUID', flat=True) - ) - return list(qs.filter(ClubID='').values_list('RoleUUID', flat=True)) + club_ids = {c for c in (allowed_club_ids or []) if c} + matched = [] + for role in Role.objects.filter(RoleStatus=1): + key = role_uuid_bytes(role.RoleUUID) + if key not in wanted: + continue + rcid = (getattr(role, 'ClubID', None) or '').strip() + if rcid == '' or rcid in club_ids: + matched.append(role.RoleUUID) + return matched + cid = (club_id or CLUB_ID_DEFAULT).strip() - # 本俱乐部专属角色 + 全局角色(权限取并集;002ac 等常在全局角色上) - return list(qs.filter(Q(ClubID=cid) | Q(ClubID='')).values_list('RoleUUID', flat=True)) + matched = [] + for role in Role.objects.filter(RoleStatus=1, ClubID=cid): + if role_uuid_bytes(role.RoleUUID) in wanted: + matched.append(role.RoleUUID) + return matched -def resolve_permission_codes_for_club(user, club_id, allowed_club_ids=None): - """指定俱乐部 SINGLE 视图下用户的 gvsdsdk 权限码。""" +def resolve_permission_codes_for_club(user, club_id, allowed_club_ids=None, scope=None): + """当前俱乐部上下文下的 gvsdsdk 权限码(与 verify_kefu_permission / 菜单共用)。""" from jituan.constants import DATA_SCOPE_SINGLE from gvsdsdk.models import Permission as SdkPermission, RolePermission as SdkRolePermission, UserRole as SdkUserRole + eff_scope = scope or DATA_SCOPE_SINGLE role_uuids = list(SdkUserRole.objects.filter( UserUUID=user.UserUUID, ).values_list('RoleUUID', flat=True)) role_uuids = filter_role_uuids_for_club_scope( - role_uuids, club_id, DATA_SCOPE_SINGLE, allowed_club_ids, + role_uuids, club_id, eff_scope, allowed_club_ids, ) if not role_uuids: return [] @@ -176,6 +186,13 @@ def resolve_permission_codes_for_club(user, club_id, allowed_club_ids=None): ) +def resolve_effective_permission_codes(user, club_id, scope, allowed_club_ids=None): + """菜单与各业务接口统一权限码:仅当前俱乐部 gvsdsdk 角色,不串其他俱乐部。""" + return resolve_permission_codes_for_club( + user, club_id, allowed_club_ids, scope=scope, + ) + + def user_bound_role_names(user, club_id=None, scope=None, allowed_club_ids=None): from backend.utils import _legacy_backend_role_permissions diff --git a/jituan/services/kefu_menu.py b/jituan/services/kefu_menu.py index aa40d12..ed69e10 100644 --- a/jituan/services/kefu_menu.py +++ b/jituan/services/kefu_menu.py @@ -132,8 +132,8 @@ def build_menu_access_payload(request, username=None): visible_ids.append(page.page_id) club_ctx = build_admin_club_context(request.user) - club_id = resolve_club_id_from_request(request) - scope = resolve_club_scope(request) + club_id = getattr(request, 'club_id', None) or resolve_club_id_from_request(request) + scope = getattr(request, 'club_scope', None) or resolve_club_scope(request) allowed = list(get_allowed_club_ids(request.user)) path_by_id = {p.page_id: p.path for p in pages if p.path} visible_paths = [path_by_id[pid] for pid in visible_ids if pid in path_by_id] diff --git a/users/views/kefu_orders.py b/users/views/kefu_orders.py index 315045a..7d71682 100644 --- a/users/views/kefu_orders.py +++ b/users/views/kefu_orders.py @@ -56,7 +56,7 @@ from orders.utils import ( from backend.utils import ( update_dashou_daily_by_action, update_guanshi_daily_by_action, update_shangjia_daily, update_zuzhang_daily_by_action, - verify_kefu_permission, has_perm_code, + verify_kefu_permission, has_merchant_order_permission, has_perm_code, ) from rank.utils import get_tag_fee, create_shenhe_jilu, validate_shenheguan @@ -304,15 +304,7 @@ class KefuGetShangjiaOrderListView(APIView): if kefu is None: return permissions - from jituan.constants import CLUB_ID_DEFAULT - from jituan.services.admin_context import get_allowed_club_ids - from jituan.services.club_rbac import resolve_permission_codes_for_club - - club_id = getattr(request, 'club_id', None) or CLUB_ID_DEFAULT - eff_codes = resolve_permission_codes_for_club( - request.user, club_id, list(get_allowed_club_ids(request.user)), - ) - if not has_perm_code(permissions, '002ac') and '002ac' not in eff_codes: + if not has_merchant_order_permission(permissions): return Response({'code': 403, 'msg': '您无权查看商家订单列表'}) # 4. 获取分页和筛选参数