كيف يمكنني تحديد متى يكون لدى المستخدم مهلة خاملة في جانغو؟

StackOverflow https://stackoverflow.com/questions/644471

  •  22-07-2019
  •  | 
  •  

سؤال

أرغب في التدقيق عندما يواجه المستخدم مهلة خاملة في تطبيق Django الخاص بي.بمعنى آخر، إذا تجاوز تاريخ انتهاء صلاحية ملف تعريف ارتباط جلسة المستخدم SESSION_COOKIE_AGE الموجود في settings.py، فسيتم إعادة توجيه المستخدم إلى صفحة تسجيل الدخول.وعندما يحدث ذلك، يجب إجراء التدقيق أيضًا.بواسطة "التدقيق"، أعني أنه يجب كتابة السجل في جدول التدقيق الخاص بي.

لقد قمت حاليًا بتكوين بعض البرامج الوسيطة لالتقاط هذه الأحداث.لسوء الحظ، يقوم Django بإنشاء ملف تعريف ارتباط جديد عند إعادة توجيه المستخدم إلى صفحة تسجيل الدخول، لذلك لا يمكنني تحديد ما إذا تم نقل المستخدم إلى صفحة تسجيل الدخول عبر مهلة خاملة أو أي حدث آخر.

مما يمكنني قوله، سأحتاج إلى العمل مع جدول "Django_session".ومع ذلك، لا يمكن ربط السجلات الموجودة في هذا الجدول بهذا المستخدم لأنه تتم إعادة تعيين قيمة معرف الجلسة في ملف تعريف الارتباط عند حدوث إعادة التوجيه.

أعتقد أنني لست أول من يواجه هذه المعضلة.هل لدى أي شخص فكرة عن كيفية حل المشكلة؟

هل كانت مفيدة؟

المحلول

تحديث:

بعد قليل من الاختبار، أدركت أن الكود أدناه لا يجيب على سؤالك.على الرغم من أنه يعمل، ويتم استدعاء معالج الإشارة، prev_session_data إذا كان موجودا، فلن يحتوي على أي معلومات مفيدة.

أولاً، نظرة خاطفة من الداخل على إطار عمل الجلسات:

  1. عندما يطلب زائر جديد عنوان URL للتطبيق، يتم إنشاء جلسة جديدة له - وفي هذه المرحلة، يظل مجهول الهوية (request.user هو مثيل AnonymousUser).
  2. إذا طلبوا عرضًا يتطلب المصادقة، فستتم إعادة توجيههم إلى عرض تسجيل الدخول.
  3. عندما يتم طلب عرض تسجيل الدخول، فإنه يقوم بتعيين قيمة اختبار في جلسة المستخدم (SessionStore._session);يؤدي هذا تلقائيًا إلى ضبط accessed و modified أعلام على الجلسة الحالية.
  4. خلال مرحلة الاستجابة للطلب أعلاه، تم SessionMiddleware يحفظ الجلسة الحالية وينشئ جلسة جديدة بشكل فعال Session المثال في django_session table (إذا كنت تستخدم الجلسات الافتراضية المدعومة بقاعدة البيانات، والتي يوفرها django.contrib.sessions.backends.db).يتم حفظ معرف الجلسة الجديدة في ملف settings.SESSION_COOKIE_NAME بسكويت.
  5. عندما يكتب المستخدم اسم المستخدم وكلمة المرور الخاصة به ويرسل النموذج، تتم مصادقتهما.إذا نجحت المصادقة، فإن login الطريقة من django.contrib.auth يسمى. login يتحقق مما إذا كانت الجلسة الحالية تحتوي على معرف مستخدم؛إذا كان الأمر كذلك، وكان المعرف هو نفس معرف المستخدم الذي قام بتسجيل الدخول، SessionStore.cycle_key يتم استدعاؤه لإنشاء مفتاح جلسة جديد، مع الاحتفاظ ببيانات الجلسة.خلاف ذلك، SessionStore.flush يتم استدعاء لإزالة كافة البيانات وإنشاء جلسة جديدة.يجب أن تقوم كلتا الطريقتين بحذف الجلسة السابقة (للمستخدم المجهول)، والاتصال SessionStore.create لإنشاء جلسة جديدة.
  6. عند هذه النقطة، تتم مصادقة المستخدم، ولديه جلسة جديدة.ويتم حفظ معرفهم في الجلسة، جنبًا إلى جنب مع الواجهة الخلفية المستخدمة لمصادقتهم.تقوم البرامج الوسيطة للجلسة بحفظ هذه البيانات في قاعدة البيانات، وتحفظ معرف الجلسة الجديد فيها settings.SESSION_COOKIE_NAME.

إذن كما ترى، المشكلة الكبيرة في الحل السابق هي الوقت create يتم الاتصال به (الخطوة 5.)، وقد اختفى معرف الجلسة السابقة منذ فترة طويلة.مثل وأشار آخرون, يحدث هذا لأنه بمجرد انتهاء صلاحية ملف تعريف ارتباط الجلسة، يتم حذفه بصمت بواسطة المتصفح.

بناء على اقتراح أليكس جاينور, ، أعتقد أنني توصلت إلى نهج آخر، يبدو أنه يفي بما تطلبه، على الرغم من أنه لا يزال صعبًا بعض الشيء حول الحواف.في الأساس، أستخدم ملف تعريف الارتباط "التدقيق" الثاني طويل الأمد، لعكس معرف الجلسة، وبعض البرامج الوسيطة للتحقق من وجود ملف تعريف الارتباط هذا.لأي طلب:

  • في حالة عدم وجود ملف تعريف ارتباط التدقيق أو ملف تعريف ارتباط الجلسة، فمن المحتمل أن يكون هذا مستخدمًا جديدًا
  • إذا كان ملف تعريف ارتباط التدقيق موجودًا، ولكن ملف تعريف ارتباط الجلسة غير موجود، فمن المحتمل أن يكون هذا مستخدمًا انتهت صلاحية جلسته للتو
  • إذا كان كلا ملفي تعريف الارتباط موجودين، ولهما نفس القيمة، فهذه جلسة نشطة

إليك الرمز حتى الآن:

sessionaudit.middleware.py:

from django.conf import settings
from django.db.models import signals
from django.utils.http import cookie_date
import time

session_expired = signals.Signal(providing_args=['previous_session_key'])

AUDIT_COOKIE_NAME = 'sessionaudit'

class SessionAuditMiddleware(object):
    def process_request(self, request):
        # The 'print' statements are helpful if you're using the development server
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
        audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
        if audit_cookie is None and session_key is None:
            print "** Got new user **"
        elif audit_cookie and session_key is None:
            print "** User session expired, Session ID: %s **" % audit_cookie
            session_expired.send(self.__class__, previous_session_key=audit_cookie)
        elif audit_cookie == session_key:
            print "** User session active, Session ID: %s **" % audit_cookie

    def process_response(self, request, response):
        if request.session.session_key:
            audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
            if audit_cookie != request.session.session_key:
                # New Session ID - update audit cookie:
                max_age = 60 * 60 * 24 * 365  # 1 year
                expires_time = time.time() + max_age
                expires = cookie_date(expires_time)
                response.set_cookie(
                    AUDIT_COOKIE_NAME,
                    request.session.session_key,
                    max_age=max_age,
                    expires=expires,
                    domain=settings.SESSION_COOKIE_DOMAIN,
                    path=settings.SESSION_COOKIE_PATH,
                    secure=settings.SESSION_COOKIE_SECURE or None
                )
        return response

Audit.models.py:

from django.contrib.sessions.models import Session
from sessionaudit.middleware import session_expired

def audit_session_expire(sender, **kwargs):
    try:
        prev_session = Session.objects.get(session_key=kwargs['previous_session_key'])
        prev_session_data = prev_session.get_decoded()
        user_id = prev_session_data.get('_auth_user_id')
    except Session.DoesNotExist:
        pass

session_expired.connect(audit_session_expire)

settings.py:

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'sessionaudit.middleware.SessionAuditMiddleware',
    ...
)

INSTALLED_APPS = (
    ...
    'django.contrib.sessions',
    'audit',
    ...
)

إذا كنت تستخدم هذا، فيجب عليك تنفيذ طريقة عرض تسجيل خروج مخصصة، والتي تحذف بشكل صريح ملف تعريف ارتباط التدقيق عندما يقوم المستخدم بتسجيل الخروج.أقترح أيضًا استخدام البرنامج الوسيط لملفات تعريف الارتباط الموقعة من Django (لكن من المحتمل أنك تفعل ذلك بالفعل، أليس كذلك؟)

قديم:

أعتقد أنك يجب أن تكون قادرًا على القيام بذلك باستخدام الواجهة الخلفية للجلسة المخصصة.إليك بعض نماذج التعليمات البرمجية (غير المختبرة):

from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.db.models import signals

session_created = signals.Signal(providing_args=['previous_session_key', 'new_session_key'])

class SessionStore(DBStore):
    """
    Override the default database session store.

    The `create` method is called by the framework to:
    * Create a new session, if we have a new user
    * Generate a new session, if the current user's session has expired

    What we want to do is override this method, so we can send a signal
    whenever it is called.
    """

    def create(self):
        # Save the current session ID:
        prev_session_id = self.session_key
        # Call the superclass 'create' to create a new session:
        super(SessionStore, self).create()
        # We should have a new session - raise 'session_created' signal:
        session_created.send(self.__class__, previous_session_key=prev_session_id, new_session_key=self.session_key)

احفظ الكود أعلاه باسم "customdb.py" وأضفه إلى مشروع django الخاص بك.في settings.py، قم بتعيين أو استبدال "SESSION_ENGINE" بالمسار إلى الملف أعلاه، على سبيل المثال:

SESSION_ENGINE = 'yourproject.customdb'

ثم في الخاص بك الوسيطة، أو models.py، قم بتوفير معالج للإشارة "session_created"، كما يلي:

from django.contrib.sessions.models import Session
from yourproject.customdb import session_created

def audit_session_expire(sender, **kwargs):
    # remember that 'previous_session_key' can be None if we have a new user
    try:
        prev_session = Session.objects.get(kwargs['previous_session_key'])
        prev_session_data = prev_session.get_decoded()
        user_id = prev_session_data['_auth_user_id']
        # do something with the user_id
    except Session.DoesNotExist:
        # new user; do something else...

session_created.connect(audit_session_expire)

لا تنس تضمين التطبيق الذي يحتوي على models.py في INSTALLED_APPS.

نصائح أخرى

وSESSION_COOKIE_AGE = 1500 # 25 دقيقة

والتي وضعت في الإعدادات الخاصة بك والتي يجب أن تأخذ الرعاية من ذلك، وتنتهي الدورة.

وأنا لا أعرف عن جانغو، ولكن يمكنك ببساطة إنشاء ملف تعريف الارتباط غير مستمر، الذي يخزن وقت وصول الأخير إلى صفحة على موقع الويب الخاص بك (تقوم بتحديث ملف تعريف الارتباط على كل تحميل الصفحة)

وبعد ذلك، على صفحة تسجيل الدخول الخاصة بك، يمكنك معرفة ما اذا كان المستخدم لديه ملف تعريف الارتباط، ولكن لم جلسة، ثم، وانت تعرف تلك الدورة المستخدم وربما مهلة. منذ كان لديك الوقت من الماضي الوصول إلى صفحة على موقع الويب الخاص بك، يمكنك أيضا حساب، استنادا إلى مدة الدورة، إذا كان توقيت ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top