You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

13 KiB

راهنمای گرفتن توکن و ورود کلاینت به کلاس‌های plugNmeet

این راهنما خلاصه می‌کند که برای سناریوی استاد/دانشجو چگونه از سرویس plugNmeet توکن بگیریم و کلاینت فرانت‌اند (client/) با آن وارد کلاس شود.

پیش‌نیازها

  • آدرس سرویس: window.PLUG_N_MEET_SERVER_URL = "https://meet.newhorizonco.uk" (در config.js).
  • api_key و secret از فایل پیکربندی بک‌اند (services/plugnmeet-server/config.yaml).
  • بدنهٔ درخواست‌ها باید با پروتکل JSON متناظر با پیام‌های پروتوباف (plugnmeet-protocol) ارسال شود؛ سرور طبق HandleAuthHeaderCheck هدرهای امنیتی را بررسی می‌کند.

گام ۱: ایجاد یا فعال بودن اتاق

API Endpoint برای Django Backend:

POST /api/courses/<course-slug>/online/room/create/

بدنه درخواست از فرانت به Django:

{
  "subject": "کلاس جبر فصل ۱"         // اختیاری - عنوان روم
}

⚠️ نکات مهم:

  • فرانت نباید metadata ارسال کند!
  • بک‌اند Django (در apps/course/views/live_session.py) به‌طور خودکار تنظیمات امنیتی را اعمال می‌کند
  • این تضمین می‌کند که تنظیمات امنیتی به‌صورت متمرکز و یکسان اعمال شود

بدنه درخواست از Django به PlugNMeet (خودکار):

بک‌اند Django این بدنه را خودش به PlugNMeet ارسال می‌کند:

{
  "room_id": "algebra-1402",
  "metadata": {
    "room_title": "کلاس جبر فصل ۱",
    "default_lock_settings": {
      "lock_microphone": true,      // 🔒 قفل - فقط میزبان می‌تواند باز کند
      "lock_webcam": true,          // 🔒 قفل - فقط میزبان می‌تواند باز کند
      "lock_screen_sharing": true   // 🔒 قفل - فقط میزبان می‌تواند باز کند
    },
    "room_features": {
      "mute_on_start": true,        // 🔇 همه با میک خاموش وارد می‌شوند
      "waiting_room_features": {
        "is_active": false
      }
    }
  }
}

چرا بک‌اند این کار را می‌کند؟

  • امنیت متمرکز: تنظیمات امنیتی در یک جا کنترل می‌شود
  • جلوگیری از دستکاری: فرانت نمی‌تواند تنظیمات را تغییر دهد
  • یکپارچگی: همه کلاس‌ها با تنظیمات یکسان ساخته می‌شوند
  • 🔒 طبق تابع AssignLockSettingsToUser در pkg/models/user_lock.go این مقادیر برای کاربران غیر-admin اعمال می‌شود

گام ۲: گرفتن توکن ورود

API Endpoint برای Django Backend:

POST /api/courses/online/room/token/

درخواست از فرانت به Django:

Headers:
  Authorization: Token <USER_TOKEN>
  Content-Type: application/json

Body:
{
  "course_slug": "algebra-10"
}

⚠️ نکات مهم:

  • فرانت فقط course_slug ارسال می‌کند!
  • بک‌اند Django از Authorization header کاربر را شناسایی می‌کند
  • بک‌اند خودش live session فعال دوره را پیدا می‌کند:
    # 1. پیدا کردن دوره
    course = Course.objects.get(slug=course_slug)
      
    # 2. پیدا کردن live session فعال
    session = CourseLiveSession.objects.get(
        course=course,
        ended_at__isnull=True  # session هایی که هنوز به پایان نرسیده‌اند
    )
      
    # 3. گرفتن room_id
    room_id = session.room_id
    
  • بک‌اند خودش همه اطلاعات کاربر را می‌سازد:
    • user_id از request.user
    • name از user.get_full_name() یا user.email
    • is_admin از user.can_manage_course(course)
    • profilePic از user.avatar
    • lock_settings برای غیر-admin

بدنه درخواست از Django به PlugNMeet (خودکار):

بک‌اند Django این payload را خودش می‌سازد و به PlugNMeet می‌فرستد:

برای استاد:

{
  "room_id": "algebra-1402",
  "user_info": {
    "user_id": "10",                    // 🔐 از request.user
    "name": "استاد نمونه",              // 🔐 از user.get_full_name()
    "is_admin": true,                   // 🔐 از user.can_manage_course()
    "user_metadata": {
      "is_hidden": false,
      "profilePic": "https://..."       // 🔐 از user.avatar
    }
  }
}

برای دانشجو:

{
  "room_id": "algebra-1402",
  "user_info": {
    "user_id": "27",                    // 🔐 از request.user
    "name": "دانشجو نمونه",             // 🔐 از user.get_full_name()
    "is_admin": false,                  // 🔐 از user.can_manage_course()
    "user_metadata": {
      "profilePic": "https://...",      // 🔐 از user.avatar
      "lock_settings": {                // 🔒 خودکار برای غیر-admin
        "lock_microphone": true,
        "lock_screen_sharing": true,
        "lock_webcam": true
      }
    }
  }
}

نحوه کار بک‌اند Django:

# 1. شناسایی کاربر از token
user = request.user  # از Authorization header

# 2. پیدا کردن دوره و session فعال
course = Course.objects.get(slug=course_slug)
session = CourseLiveSession.objects.get(course=course, ended_at__isnull=True)
room_id = session.room_id

# 3. تشخیص نقش
is_admin = user.can_manage_course(course)  # استاد یا مالک دوره

# 4. ساخت user_info
user_info = {
    'user_id': str(user.id),
    'name': user.get_full_name() or user.email,
    'is_admin': is_admin,
}

# 4. اضافه کردن profilePic
profile_pic = request.build_absolute_uri(user.avatar.url)
user_metadata['profilePic'] = profile_pic

# 5. اضافه کردن lock_settings برای غیر-admin
if not is_admin:
    user_metadata['lock_settings'] = {
        'lock_microphone': True,
        'lock_screen_sharing': True,
        'lock_webcam': True,
    }

ارسال به PlugNMeet:

بک‌اند Django با هدرهای امنیتی به PlugNMeet ارسال می‌کند:

  • API-KEY: از settings
  • HASH-SIGNATURE: HMAC_SHA256(body, secret)
  • این توکن JWT اختصاصی plugNmeet است که در GeneratePNMJoinToken ساخته می‌شود
  • is_admin: true باعث می‌شود در GetPNMJoinToken کاربر به عنوان presenter با تمام دسترسی‌ها ثبت شود
  • lock_settings باعث می‌شود در فرانت‌اند PlugNMeet دکمه‌های میکروفون/وبکم غیرفعال شوند

پاسخ Django به فرانت:

{
  "room_id": "algebra-1402",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "plugnmeet": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires": 300,
    ...
  }
}

فرانت با این token می‌تواند کاربر را به PlugNMeet وارد کند:

https://meet.newhorizonco.uk/?access_token=<TOKEN>

گام ۳: ورود کلاینت با توکن

۱. توکن را در URL یا کوکی قرار دهید؛ کلاینت مقدار را از access_token در کوئری‌استرینگ یا از کوکی pnm_access_token می‌خواند (getAccessToken در client/src/helpers/utils.ts). ۲. آدرس ورود: https://meet.newhorizonco.uk/?access_token=<TOKEN>. ۳. اپلیکیشن React موجود در client/src/components/app/index.tsx پس از بارگذاری:

  • درخواست POST /api/verifyToken را با هدر Authorization: <TOKEN> می‌فرستد (HandleVerifyToken).
  • اگر توکن معتبر باشد، لیست آدرس‌های NATS و موضوعات لازم را می‌گیرد و اتصال را آغاز می‌کند (startNatsConn). ۴. پس از اتصال، وضعیت کاربر و اتاق در Redux ذخیره می‌شود (sessionSlice). اگر کاربر ادمین باشد، تمام امکانات بدون محدودیت فعال است؛ در غیر این صورت مقدارهای lock_settings تعیین می‌کنند چه دکمه‌هایی فعال باشند.

کنترل حالت صحبت/شنیدن برای استاد و دانشجو

استاد (Moderator/Host):

  • در توکن is_admin: true ارسال می‌شود
  • بک‌اند Django در apps/course/views/live_session.py این را تشخیص می‌دهد:
    is_admin = user.can_manage_course(course)  # استاد یا مالک دوره
    
  • سرور PlugNMeet در GetPNMJoinToken رول presenter را فعال می‌کند
  • هیچ قفلی روی میکروفون، وبکم یا اشتراک صفحه اعمال نمی‌شود
  • 🎤 استاد می‌تواند بلافاصله صحبت کند و به دانشجو اجازه صحبت دهد

دانشجو (Participant):

  • 🔒 در توکن is_admin: false ارسال می‌شود
  • 🔒 بک‌اند Django خودکار lock_settings را اضافه می‌کند:
    if not is_admin:
        user_metadata['lock_settings'] = {
            'lock_microphone': True,
            'lock_screen_sharing': True,
            'lock_webcam': True,
        }
    
  • 🔇 دکمه‌های میکروفون، وبکم و اشتراک صفحه غیرفعال هستند
  • 👂 فقط می‌تواند گوش دهد تا میزبان اجازه دهد
  • این منطق در joinModal.tsx با متغیر isMicLock پیاده‌سازی شده است

نحوه دادن اجازه به دانشجو:

  • میزبان باید از داخل کلاس از طریق UI کنترل کند
  • یا از API /api/updateLockSettings یا switchPresenter استفاده کند

نکات تکمیلی

توکن‌ها و انقضا:

  • توکن‌ها زمان انقضای مفهومی دارند (client.token_validity در YAML)
  • در صورت نزدیک شدن به انقضا، کلاینت خودکار با REQ_RENEW_PNM_TOKEN درخواست تمدید می‌دهد

Authorization:

  • برای درخواست‌های بعدی به /api/... همان هدر Authorization را ست کنید
  • کلاینت این کار را در helpers/api/plugNmeetAPI.ts انجام می‌دهد

مدیریت دسترسی‌ها:

  • اگر می‌خواهید دانشجو را به صحبت‌کننده ارتقا دهید: /api/updateLockSettings یا switchPresenter
  • این کار فقط توسط میزبان امکان‌پذیر است

🔐 جمع‌بندی امنیت

چیزهایی که فرانت نباید انجام دهد:

موقع ساخت روم:

  • ارسال metadata
  • ارسال default_lock_settings
  • ارسال room_features

موقع گرفتن توکن:

  • ارسال room_id (بک‌اند خودش از session فعال می‌گیرد)
  • ارسال user_info
  • ارسال is_admin
  • ارسال lock_settings
  • ارسال user_id یا name

چیزهایی که فرانت فقط ارسال می‌کند:

موقع ساخت روم:

{
  "room_id": "algebra-1402",  // اختیاری
  "subject": "کلاس جبر"       // اختیاری
}

موقع گرفتن توکن:

{
  "course_slug": "algebra-10"   // فقط این!
}
  • Authorization: Token <USER_TOKEN> در header

چیزهایی که بک‌اند Django خودش انجام می‌دهد:

برای همه درخواست‌ها:

  • شناسایی کاربر از Authorization header
  • بررسی دسترسی با user.can_manage_course() یا Participant.objects.filter()

موقع ساخت روم:

  • تعیین default_lock_settings (همه true)
  • تعیین room_features.mute_on_start: true
  • ساخت metadata کامل برای PlugNMeet

موقع گرفتن توکن:

  • پیدا کردن live session فعال از course_slug
  • گرفتن room_id از session
  • ساخت user_id از request.user.id
  • ساخت name از user.get_full_name() یا user.email
  • تشخیص is_admin از user.can_manage_course(course)
  • گرفتن profilePic از user.avatar
  • اضافه کردن lock_settings برای غیر-admin
  • ساخت user_info کامل برای PlugNMeet

نتیجه:

  • 🔒 امنیت کامل: فرانت نمی‌تواند هیچ تنظیمات امنیتی را دستکاری کند
  • متمرکز: همه logic در بک‌اند Django است
  • 🎯 ساده: فرانت فقط course_slug و Authorization header ارسال می‌کند
  • 🔐 قابل کنترل: بک‌اند تعیین می‌کند کدام session فعال است