From 4963b06e21381e5c7b0702a3d144a5baf3246ef7 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 19 Jun 2026 13:08:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E6=9D=83=E9=99=90=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/utils.py | 8 ----- users/views.py | 81 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/backend/utils.py b/backend/utils.py index 118d399..ba465bc 100644 --- a/backend/utils.py +++ b/backend/utils.py @@ -140,14 +140,6 @@ def verify_kefu_permission(request, username_from_frontend=None): if '000001' in permissions: permissions = _AllPermissions(permissions) - # 临时调试日志 — 诊断管理员权限问题 - logger.warning( - f"[权限调试] Phone={current_user.Phone} UserType={current_user.UserType} " - f"IsSuperuser={current_user.IsSuperuser} is_admin={is_admin} " - f"perms_type={type(permissions).__name__} perms_len={len(permissions)} " - f"has_000001={'000001' in permissions} is_AllPerm={isinstance(permissions, _AllPermissions)}" - ) - if not permissions: logger.warning(f"用户 {current_user.Phone} 没有任何权限,请检查角色分配") diff --git a/users/views.py b/users/views.py index 7a35e10..82caf51 100644 --- a/users/views.py +++ b/users/views.py @@ -6706,13 +6706,15 @@ class ShangjiaChufaJiluHuoquView(APIView): class KefuLoginView(APIView): """ - 客服登录接口(支持手机号重复) + 客服/管理员登录接口(支持手机号重复) 请求:POST /yonghu/kefujinru 请求体:{"phone": "13800138000", "password": "xxx", "erjimima": "yyy"} 返回: code=0 成功,data包含token,nicheng,yonghuid - code=4 账号被封禁(提示“账号已被封禁”) - 其他错误统一 code=1 msg="登录失败" + code=1 失败(msg区分:用户不存在/密码错误/二级密码错误) + code=4 账号被封禁 + + 管理员(IsSuperuser 或 UserType='admin')无需 erjimima 和 KefuProfile。 """ throttle_classes = [AnonRateThrottle] # 限制匿名请求频率 permission_classes = [AllowAny] # 任何人都可访问 @@ -6723,41 +6725,61 @@ class KefuLoginView(APIView): password = request.data.get('password', '') erjimima = request.data.get('erjimima', '') - if not phone or not password or not erjimima: + if not phone or not password: return Response({ 'code': 1, - 'msg': '登录失败', # 统一提示,不暴露具体原因 + 'msg': '请填写手机号和密码', 'data': None }, status=status.HTTP_400_BAD_REQUEST) # 2. 获取客户端真实IP client_ip = self.get_client_ip(request) - # 3. 查询该手机号下所有客服账号(User 字段为 Phone,与 backend 创建客服校验写法一致) - user_mains = User.query.filter( - Phone=phone, - KefuProfile__isnull=False, - ).select_related('KefuProfile') + # 3. 查询该手机号下所有账号(客服 + 管理员) + # 先查客服(有 KefuProfile),再查管理员(IsSuperuser 或 UserType='admin') + user_mains = list( + User.query.filter( + Phone=phone, + KefuProfile__isnull=False, + ).select_related('KefuProfile') + ) - if not user_mains.exists(): - logger.warning(f"登录失败,手机号不存在或非客服: {phone}, IP: {client_ip}") + # 如果没有客服账号,尝试查找管理员账号 + if not user_mains: + admin_candidates = User.query.filter(Phone=phone) + for admin_user in admin_candidates: + if admin_user.IsSuperuser or admin_user.UserType == 'admin': + user_mains = [admin_user] + break + + if not user_mains: + logger.warning(f"登录失败,用户不存在: {phone}, IP: {client_ip}") return Response({ 'code': 1, - 'msg': '登录失败', + 'msg': '用户不存在', 'data': None }, status=status.HTTP_400_BAD_REQUEST) - # 4. 遍历所有匹配的客服账号,验证密码和二级密码 + # 4. 遍历所有匹配的账号,验证密码和二级密码 target_user = None target_kefu = None + password_matched = False for user in user_mains: - kefu = user.KefuProfile # 验证主密码(bcrypt 哈希验证) if not user.CheckPassword(password): continue + password_matched = True - # 验证二级密码(兼容 bcrypt 哈希和明文) + # 管理员:跳过二级密码和客服扩展表检查 + is_admin = user.IsSuperuser or user.UserType == 'admin' + if is_admin: + target_user = user + target_kefu = None + break + + # 客服:验证二级密码 + kefu = user.KefuProfile stored_erji = kefu.erjimima or '' if stored_erji.startswith(('$2b$', '$2a$')) and len(stored_erji) == 60: import bcrypt as _bcrypt @@ -6766,11 +6788,9 @@ class KefuLoginView(APIView): elif stored_erji != erjimima: continue - # 如果账号被禁用,记录但继续查找(可能还有其他正常账号?) + # 如果账号被禁用,记录但继续查找 if kefu.zhuangtai != 1: - # 如果找到被禁用的,记录下来,但继续查找是否有正常账号 if target_user is None: - # 暂时记录这个禁用账号,但继续遍历 target_user = user target_kefu = kefu continue @@ -6780,7 +6800,7 @@ class KefuLoginView(APIView): target_kefu = kefu break else: - # 循环结束未找到正常账号,但可能找到了禁用账号 + # 循环结束未找到正常账号 if target_user and target_kefu: # 只有被禁用的账号匹配,返回封禁提示 logger.warning(f"登录失败,客服账号已禁用: {phone}, IP: {client_ip}") @@ -6789,12 +6809,20 @@ class KefuLoginView(APIView): 'msg': '账号已被封禁', 'data': None }, status=status.HTTP_403_FORBIDDEN) - else: - # 没有任何账号匹配(密码/二级密码错误) - logger.warning(f"登录失败,密码或二级密码错误: {phone}, IP: {client_ip}") + elif password_matched: + # 密码正确但二级密码错误 + logger.warning(f"登录失败,二级密码错误: {phone}, IP: {client_ip}") return Response({ 'code': 1, - 'msg': '登录失败', + 'msg': '二级密码错误', + 'data': None + }, status=status.HTTP_400_BAD_REQUEST) + else: + # 密码错误 + logger.warning(f"登录失败,密码错误: {phone}, IP: {client_ip}") + return Response({ + 'code': 1, + 'msg': '密码错误', 'data': None }, status=status.HTTP_400_BAD_REQUEST) @@ -6807,13 +6835,14 @@ class KefuLoginView(APIView): refresh = RefreshToken.for_user(target_user) token = str(refresh.access_token) - # 7. 返回成功数据 + # 7. 返回成功数据(管理员无 KefuProfile,nicheng 用 UserName 或 Phone 兜底) + nicheng = target_kefu.nicheng if target_kefu else (target_user.UserName or target_user.Phone) return Response({ 'code': 0, 'msg': '登录成功', 'data': { 'token': token, - 'nicheng': target_kefu.nicheng, + 'nicheng': nicheng, 'yonghuid': target_user.UserUID, } })