# management/backends.py # -*- coding: utf-8 -*- import asyncio import logging from django.contrib.auth.backends import BaseBackend from django.contrib.auth import get_user_model from marzban_api.marzban_client import Marzban from marzban_api.exceptions import AuthenticationError, MarzbanAPIError from .models import MarzbanAdmin, MarzbanUser, Panel, Role CustomUser = get_user_model() logger = logging.getLogger(__name__) class CustomMarzbanBackend(BaseBackend): """ بک‌اند احراز هویت که admin_id و اطلاعات ادمین را از دیتابیس مرزبان پیدا می‌کند. """ def authenticate(self, request, username=None, **kwargs): if not username: return None try: # 1. پیدا کردن admin_id از دیتابیس مرزبان marzban_user = MarzbanUser.objects.using('marzban_db').get(username=username) admin_id = marzban_user.admin_id if not admin_id: logger.warning(f"User {username} has no associated admin in Marzban DB.") return None # 2. پیدا کردن اطلاعات ادمین از دیتابیس مرزبان try: admin_obj = MarzbanAdmin.objects.using('marzban_db').get(id=admin_id) except MarzbanAdmin.DoesNotExist: logger.error(f"Admin with ID {admin_id} not found in Marzban DB.") return None admin_username = admin_obj.username admin_password = admin_obj.password # 3. لاگین به API مرزبان با مشخصات ادمین و تایید وجود کاربر async def authenticate_with_marzban(): # در این مرحله، آدرس پنل باید از یک مکان مشخص (مثلاً مدل Panel) خوانده شود. # برای سادگی، فعلا یک آدرس پیش‌فرض در نظر می‌گیریم. panel_address = 'http://your_marzban_panel_address.com' try: async with Marzban(admin_username, admin_password, panel_address) as marzban_client: await marzban_client.login_admin() await marzban_client.get_user_info(username) # 4. ایجاد یا دریافت کاربر در دیتابیس لوکال و اختصاص نقش user, created = CustomUser.objects.get_or_create(username=username) if created: user_role, _ = Role.objects.get_or_create(name=Role.USER) user.role = user_role user.save() return user except AuthenticationError as e: logger.error(f"Marzban API authentication failed for admin {admin_username}: {e}") return None except MarzbanAPIError as e: logger.error(f"User {username} not found in Marzban via admin {admin_username}: {e}") return None except Exception as e: logger.error(f"An unknown error occurred during Marzban API authentication: {e}") return None authenticated_user = asyncio.run(authenticate_with_marzban()) if authenticated_user: return authenticated_user except MarzbanUser.DoesNotExist: logger.warning(f"User {username} not found in Marzban database.") return None except Exception as e: logger.error(f"An unknown error occurred: {e}") return None def get_user(self, user_id): try: return CustomUser.objects.get(pk=user_id) except CustomUser.DoesNotExist: return None