File size: 3,929 Bytes
3e8a166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# 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