كيف يمكنني تحديد متى يكون لدى المستخدم مهلة خاملة في جانغو؟
-
22-07-2019 - |
سؤال
أرغب في التدقيق عندما يواجه المستخدم مهلة خاملة في تطبيق Django الخاص بي.بمعنى آخر، إذا تجاوز تاريخ انتهاء صلاحية ملف تعريف ارتباط جلسة المستخدم SESSION_COOKIE_AGE الموجود في settings.py، فسيتم إعادة توجيه المستخدم إلى صفحة تسجيل الدخول.وعندما يحدث ذلك، يجب إجراء التدقيق أيضًا.بواسطة "التدقيق"، أعني أنه يجب كتابة السجل في جدول التدقيق الخاص بي.
لقد قمت حاليًا بتكوين بعض البرامج الوسيطة لالتقاط هذه الأحداث.لسوء الحظ، يقوم Django بإنشاء ملف تعريف ارتباط جديد عند إعادة توجيه المستخدم إلى صفحة تسجيل الدخول، لذلك لا يمكنني تحديد ما إذا تم نقل المستخدم إلى صفحة تسجيل الدخول عبر مهلة خاملة أو أي حدث آخر.
مما يمكنني قوله، سأحتاج إلى العمل مع جدول "Django_session".ومع ذلك، لا يمكن ربط السجلات الموجودة في هذا الجدول بهذا المستخدم لأنه تتم إعادة تعيين قيمة معرف الجلسة في ملف تعريف الارتباط عند حدوث إعادة التوجيه.
أعتقد أنني لست أول من يواجه هذه المعضلة.هل لدى أي شخص فكرة عن كيفية حل المشكلة؟
المحلول
تحديث:
بعد قليل من الاختبار، أدركت أن الكود أدناه لا يجيب على سؤالك.على الرغم من أنه يعمل، ويتم استدعاء معالج الإشارة، prev_session_data
إذا كان موجودا، فلن يحتوي على أي معلومات مفيدة.
أولاً، نظرة خاطفة من الداخل على إطار عمل الجلسات:
- عندما يطلب زائر جديد عنوان URL للتطبيق، يتم إنشاء جلسة جديدة له - وفي هذه المرحلة، يظل مجهول الهوية (
request.user
هو مثيل AnonymousUser). - إذا طلبوا عرضًا يتطلب المصادقة، فستتم إعادة توجيههم إلى عرض تسجيل الدخول.
- عندما يتم طلب عرض تسجيل الدخول، فإنه يقوم بتعيين قيمة اختبار في جلسة المستخدم (
SessionStore._session
);يؤدي هذا تلقائيًا إلى ضبطaccessed
وmodified
أعلام على الجلسة الحالية. - خلال مرحلة الاستجابة للطلب أعلاه، تم
SessionMiddleware
يحفظ الجلسة الحالية وينشئ جلسة جديدة بشكل فعالSession
المثال فيdjango_session
table (إذا كنت تستخدم الجلسات الافتراضية المدعومة بقاعدة البيانات، والتي يوفرهاdjango.contrib.sessions.backends.db
).يتم حفظ معرف الجلسة الجديدة في ملفsettings.SESSION_COOKIE_NAME
بسكويت. - عندما يكتب المستخدم اسم المستخدم وكلمة المرور الخاصة به ويرسل النموذج، تتم مصادقتهما.إذا نجحت المصادقة، فإن
login
الطريقة منdjango.contrib.auth
يسمى.login
يتحقق مما إذا كانت الجلسة الحالية تحتوي على معرف مستخدم؛إذا كان الأمر كذلك، وكان المعرف هو نفس معرف المستخدم الذي قام بتسجيل الدخول،SessionStore.cycle_key
يتم استدعاؤه لإنشاء مفتاح جلسة جديد، مع الاحتفاظ ببيانات الجلسة.خلاف ذلك،SessionStore.flush
يتم استدعاء لإزالة كافة البيانات وإنشاء جلسة جديدة.يجب أن تقوم كلتا الطريقتين بحذف الجلسة السابقة (للمستخدم المجهول)، والاتصالSessionStore.create
لإنشاء جلسة جديدة. - عند هذه النقطة، تتم مصادقة المستخدم، ولديه جلسة جديدة.ويتم حفظ معرفهم في الجلسة، جنبًا إلى جنب مع الواجهة الخلفية المستخدمة لمصادقتهم.تقوم البرامج الوسيطة للجلسة بحفظ هذه البيانات في قاعدة البيانات، وتحفظ معرف الجلسة الجديد فيها
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 دقيقة
والتي وضعت في الإعدادات الخاصة بك والتي يجب أن تأخذ الرعاية من ذلك، وتنتهي الدورة.
وأنا لا أعرف عن جانغو، ولكن يمكنك ببساطة إنشاء ملف تعريف الارتباط غير مستمر، الذي يخزن وقت وصول الأخير إلى صفحة على موقع الويب الخاص بك (تقوم بتحديث ملف تعريف الارتباط على كل تحميل الصفحة)
وبعد ذلك، على صفحة تسجيل الدخول الخاصة بك، يمكنك معرفة ما اذا كان المستخدم لديه ملف تعريف الارتباط، ولكن لم جلسة، ثم، وانت تعرف تلك الدورة المستخدم وربما مهلة. منذ كان لديك الوقت من الماضي الوصول إلى صفحة على موقع الويب الخاص بك، يمكنك أيضا حساب، استنادا إلى مدة الدورة، إذا كان توقيت ذلك.