from rest_framework import exceptions, status from rest_framework.response import Response from rest_framework.views import exception_handler from rest_framework_simplejwt.exceptions import InvalidToken from flower.error_code import AuthErrorCode def auth_error_response(*, error_code: AuthErrorCode, code: str, message: str, http_status: int, extra=None): data = { 'error_code': int(error_code), 'code': code, 'message': message, 'detail': message, } if extra: data.update(extra) return Response(data, status=http_status) def _stringify_detail(detail): if hasattr(detail, 'code'): return str(detail), str(detail.code) return str(detail), None def _extract_exception_detail(exc): detail = getattr(exc, 'detail', None) if isinstance(detail, dict): raw_detail = detail.get('detail') raw_code = detail.get('code') messages = detail.get('messages') message = str(raw_detail) if raw_detail is not None else '' code = str(raw_code) if raw_code is not None else None extra = {'messages': messages} if messages is not None else None return message, code, extra message, code = _stringify_detail(detail) return message, code, None def custom_exception_handler(exc, context): if isinstance(exc, InvalidToken): _, _, extra = _extract_exception_detail(exc) return auth_error_response( error_code=AuthErrorCode.TOKEN_NOT_VALID, code='token_not_valid', message='Token 无效或已过期', http_status=status.HTTP_401_UNAUTHORIZED, extra=extra, ) if isinstance(exc, exceptions.NotAuthenticated): return auth_error_response( error_code=AuthErrorCode.NOT_AUTHENTICATED, code='not_authenticated', message='未提供认证凭据', http_status=status.HTTP_401_UNAUTHORIZED, ) if isinstance(exc, exceptions.AuthenticationFailed): message, code, extra = _extract_exception_detail(exc) if code == 'bad_authorization_header': return auth_error_response( error_code=AuthErrorCode.BAD_AUTHORIZATION_HEADER, code='bad_authorization_header', message='Authorization 请求头格式错误', http_status=status.HTTP_401_UNAUTHORIZED, ) if code == 'user_not_found': return auth_error_response( error_code=AuthErrorCode.TOKEN_USER_NOT_FOUND, code='token_user_not_found', message='Token 对应用户不存在', http_status=status.HTTP_401_UNAUTHORIZED, ) if code == 'user_inactive': return auth_error_response( error_code=AuthErrorCode.TOKEN_USER_INACTIVE, code='token_user_inactive', message='Token 对应用户已被禁用', http_status=status.HTTP_401_UNAUTHORIZED, ) return auth_error_response( error_code=AuthErrorCode.TOKEN_NOT_VALID, code=code or 'authentication_failed', message=message or '认证失败', http_status=status.HTTP_401_UNAUTHORIZED, extra=extra, ) if isinstance(exc, exceptions.PermissionDenied): return auth_error_response( error_code=AuthErrorCode.PERMISSION_DENIED, code='permission_denied', message='无权限访问该资源', http_status=status.HTTP_403_FORBIDDEN, ) return exception_handler(exc, context)