Làm cách nào để hết hạn phiên do không hoạt động trong Django?


93

Ứng dụng Django của chúng tôi có các yêu cầu quản lý phiên sau.

  1. Phiên hết hạn khi người dùng đóng trình duyệt.
  2. Phiên hết hạn sau một thời gian không hoạt động.
  3. Phát hiện khi một phiên hết hạn do không hoạt động và hiển thị thông báo thích hợp cho người dùng.
  4. Cảnh báo người dùng về một phiên sắp hết hạn vài phút trước khi kết thúc khoảng thời gian không hoạt động. Cùng với cảnh báo, cung cấp cho người dùng một tùy chọn để kéo dài phiên của họ.
  5. Nếu người dùng đang thực hiện một hoạt động kinh doanh dài trong ứng dụng không liên quan đến các yêu cầu được gửi đến máy chủ, thì phiên không được hết thời gian chờ.

Sau khi đọc tài liệu, mã Django và một số bài đăng trên blog liên quan đến điều này, tôi đã đưa ra phương pháp triển khai sau đây.

Yêu cầu 1 Yêu cầu
này có thể dễ dàng thực hiện bằng cách đặt SESSION_EXPIRE_AT_BROWSER_CLOSE thành True.

Yêu cầu 2
Tôi đã thấy một số khuyến nghị sử dụng SESSION_COOKIE_AGE để đặt khoảng thời gian hết hạn phiên. Nhưng phương pháp này có những vấn đề sau.

  • Phiên luôn hết hạn vào cuối SESSION_COOKIE_AGE ngay cả khi người dùng đang sử dụng ứng dụng. (Điều này có thể được ngăn chặn bằng cách đặt thời hạn phiên thành SESSION_COOKIE_AGE cho mọi yêu cầu sử dụng phần mềm trung gian tùy chỉnh hoặc bằng cách lưu phiên theo mọi yêu cầu bằng cách đặt SESSION_SAVE_EVERY_REQUEST thành true. Nhưng vấn đề tiếp theo là không thể tránh khỏi do việc sử dụng SESSION_COOKIE_AGE.)

  • Do cách thức hoạt động của cookie, SESSION_EXPIRE_AT_BROWSER_CLOSE và SESSION_COOKIE_AGE loại trừ lẫn nhau, tức là cookie sẽ hết hạn khi đóng trình duyệt hoặc vào thời gian hết hạn được chỉ định. Nếu SESSION_COOKIE_AGE được sử dụng và người dùng đóng trình duyệt trước khi cookie hết hạn, cookie sẽ được giữ lại và việc mở lại trình duyệt sẽ cho phép người dùng (hoặc bất kỳ ai khác) vào hệ thống mà không cần xác thực lại.

  • Django chỉ dựa vào cookie hiện có để xác định xem phiên có hoạt động hay không. Nó không kiểm tra ngày hết hạn phiên được lưu trữ cùng với phiên.

Phương pháp sau có thể được sử dụng để thực hiện yêu cầu này và giải quyết các vấn đề được đề cập ở trên.

  • Không đặt SESSION_COOKIE_AGE.
  • Đặt ngày hết hạn của phiên là 'thời gian hiện tại + thời gian không hoạt động' theo mọi yêu cầu.
  • Ghi đè process_request trong SessionMiddleware và kiểm tra thời hạn của phiên. Hủy phiên nếu nó đã hết hạn.

Yêu cầu 3
Khi chúng tôi phát hiện rằng phiên đã hết hạn (trong SessionMiddleware tùy chỉnh ở trên), hãy đặt một thuộc tính trên yêu cầu để cho biết phiên hết hạn. Thuộc tính này có thể được sử dụng để hiển thị một thông báo thích hợp cho người dùng.

Yêu cầu 4
Sử dụng JavaScript để phát hiện người dùng không hoạt động, đưa ra cảnh báo và cũng là một tùy chọn để kéo dài phiên. Nếu người dùng muốn gia hạn, hãy gửi một xung duy trì hoạt động đến máy chủ để kéo dài phiên.

Yêu cầu 5
Sử dụng JavaScript để phát hiện hoạt động của người dùng (trong quá trình hoạt động kinh doanh lâu dài) và gửi các xung còn sống đến máy chủ để ngăn phiên hết hạn.


Phương pháp triển khai ở trên có vẻ rất phức tạp và tôi đã tự hỏi liệu có thể có một phương pháp đơn giản hơn không (đặc biệt là cho Yêu cầu 2).

Bất kỳ hiểu biết sâu sắc sẽ được đánh giá cao.


3
+1 để cung cấp giải pháp chi tiết
Don

Có một phần mềm trung gian có thể làm những gì bạn cần. trên githubtrên pypi
gbutler

1
"Do cách hoạt động của cookie, SESSION_EXPIRE_AT_BROWSER_CLOSE và SESSION_COOKIE_AGE loại trừ lẫn nhau, tức là cookie sẽ hết hạn khi đóng trình duyệt hoặc vào thời gian hết hạn đã chỉ định. Nếu SESSION_COOKIE_AGE được sử dụng và người dùng đóng trình duyệt trước khi cookie hết hạn, cookie sẽ được giữ lại và mở lại trình duyệt sẽ cho phép người dùng (hoặc bất kỳ ai khác) vào hệ thống mà không cần xác thực lại. " Hãy sửa tôi nếu tôi sai, nhưng điều này dường như không còn đúng trong các phiên bản Django mới hơn? (Ít nhất
1,5+

1
"Django chỉ dựa vào cookie hiện có để xác định xem phiên có hoạt động hay không. Nó không kiểm tra ngày hết hạn phiên được lưu cùng với phiên." Điều này không còn đúng nữa.
knaperek

Câu trả lời:


44

Đây là một ý tưởng ... Kết thúc phiên trên trình duyệt với SESSION_EXPIRE_AT_BROWSER_CLOSEcài đặt. Sau đó, đặt dấu thời gian trong phiên đối với mọi yêu cầu như vậy.

request.session['last_activity'] = datetime.now()

và thêm phần mềm trung gian để phát hiện xem phiên có hết hạn hay không. một cái gì đó như thế này sẽ xử lý toàn bộ quá trình ...

from datetime import datetime
from django.http import HttpResponseRedirect

class SessionExpiredMiddleware:
    def process_request(request):
        last_activity = request.session['last_activity']
        now = datetime.now()

        if (now - last_activity).minutes > 10:
            # Do logout / expire session
            # and then...
            return HttpResponseRedirect("LOGIN_PAGE_URL")

        if not request.is_ajax():
            # don't set this for ajax requests or else your
            # expired session checks will keep the session from
            # expiring :)
            request.session['last_activity'] = now

Sau đó, bạn chỉ cần tạo một số url và chế độ xem để trả về dữ liệu có liên quan cho các lệnh gọi ajax liên quan đến việc hết hạn phiên.

khi người dùng chọn "gia hạn" phiên, vì vậy, có thể nói, tất cả những gì bạn phải làm là đặt requeset.session['last_activity']lại thời điểm hiện tại

Rõ ràng mã này chỉ là một bước khởi đầu ... nhưng nó sẽ giúp bạn đi đúng đường


Tôi chỉ nghi ngờ ở đây, nhưng tôi không nghĩ rằng if not request.is_ajax()nó là hoàn toàn an toàn. Không thể ai đó nắm giữ phiên trước khi hết hạn giả mạo / gửi một cuộc gọi ajax và giữ cho phiên tiếp tục?
notbad.jpeg

2
@ notbad.jpeg: nói chung "hoạt động" dễ bị giả mạo. Ai đó nắm giữ phiên và tiếp tục gửi yêu cầu chỉ đang hoạt động.
RemcoGerlich

Đây là một câu trả lời tuyệt vời. Phần mềm trung gian là một công cụ được sử dụng rất ít trong quá trình phát triển Django.
Jamie Counsell

30

Tôi chỉ mới sử dụng Django.

Tôi muốn làm cho phiên hết hạn nếu người dùng đã đăng nhập đóng trình duyệt hoặc ở trạng thái không hoạt động (hết thời gian chờ không hoạt động) trong một khoảng thời gian. Khi tôi tìm kiếm nó trên Google, câu hỏi SOF này xuất hiện đầu tiên. Nhờ câu trả lời hay, tôi đã tìm kiếm các tài nguyên để hiểu cách phần mềm trung gian hoạt động trong chu kỳ yêu cầu / phản hồi trong Django. Nó rất hữu ích.

Tôi sắp áp dụng phần mềm trung gian tùy chỉnh vào mã của mình sau câu trả lời hàng đầu ở đây. Nhưng tôi vẫn hơi nghi ngờ vì câu trả lời hay nhất ở đây đã được chỉnh sửa vào năm 2011. Tôi đã mất nhiều thời gian hơn để tìm kiếm một chút từ kết quả tìm kiếm gần đây và nghĩ ra một cách đơn giản.

SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 10 # set just 10 seconds to test
SESSION_SAVE_EVERY_REQUEST = True

Tôi đã không kiểm tra các trình duyệt khác ngoài chrome. 1. Một phiên đã hết hạn khi tôi đóng trình duyệt ngay cả khi SESSION_COOKIE_AGE được đặt. 2. Chỉ khi tôi không hoạt động trong hơn 10 giây, một phiên đã hết hạn. Nhờ SESSION_SAVE_EVERY_REQUEST, bất cứ khi nào bạn có yêu cầu mới, Nó sẽ lưu phiên và cập nhật thời gian chờ hết hạn

Để thay đổi hành vi mặc định này, hãy đặt cài đặt SESSION_SAVE_EVERY_REQUEST thành True. Khi được đặt thành True, Django sẽ lưu phiên vào cơ sở dữ liệu theo từng yêu cầu.

Lưu ý rằng cookie phiên chỉ được gửi khi một phiên đã được tạo hoặc sửa đổi. Nếu SESSION_SAVE_EVERY_REQUEST là True, cookie phiên sẽ được gửi theo mọi yêu cầu.

Tương tự, phần hết hạn của cookie phiên được cập nhật mỗi khi cookie phiên được gửi.

hướng dẫn django 1.10

Tôi chỉ để lại câu trả lời để một số người mới chơi Django như tôi không mất nhiều thời gian để tìm ra giải pháp như cách tôi đã làm.


26

django-session-security thực hiện điều đó ...

... với một yêu cầu bổ sung: nếu máy chủ không phản hồi hoặc kẻ tấn công ngắt kết nối internet: dù sao thì nó cũng sẽ hết hạn.

Disclamer: Tôi duy trì ứng dụng này. Nhưng tôi đã xem chủ đề này trong một thời gian rất dài :)


1
ứng dụng tuyệt vời - được thiết kế độc đáo và xây dựng tốt. đẹp, mã sạch ... cảm ơn bạn.
nicorellius

Nếu người dùng đóng trình duyệt hoặc tab (mà không đăng xuất) khi họ rời khỏi, nó có còn buộc người dùng đăng xuất không? Nó có xử lý được tình trạng này không?
Mehmet Kagan Kayaalp

Điều đó sẽ được xử lý bằng cách hết hạn cookie phiên thuần http phải không?
jpic

10

Một cách dễ dàng để đáp ứng yêu cầu thứ hai của bạn là đặt giá trị SESSION_COOKIE_AGE trong settings.py thành một lượng giây phù hợp. Ví dụ:

SESSION_COOKIE_AGE = 600      #10 minutes.

Tuy nhiên, bằng cách chỉ làm điều này, phiên sẽ hết hạn sau 10 phút cho dù người dùng có thực hiện một số hoạt động hay không. Để giải quyết vấn đề này, thời gian hết hạn có thể được tự động gia hạn (thêm 10 phút nữa) mỗi khi người dùng thực hiện bất kỳ loại yêu cầu nào với câu sau:

request.session.set_expiry(request.session.get_expiry_age())

2
SESSION_COOKIE_AGE = 600 Điều này sẽ kéo dài tuổi phiên với mỗi yêu cầu trang mới hoặc làm mới trang
Aseem 10/1218

1
Tôi xác nhận rằng chỉ cần thiết lập SESSION_COOKIE_AGElà đủ và bất kỳ yêu cầu nào (gửi cookie phiên) sẽ tự động làm mới khi hết hạn cookie phiên.
bruno desthuilliers


3

Trong yêu cầu đầu tiên, bạn có thể đặt thời hạn phiên là

self.request.session['access_key'] = access_key
self.request.session['access_token'] = access_token
self.request.session.set_expiry(set_age) #in seconds 

Và khi sử dụng access_key và mã thông báo,

try:
    key = self.request.session['access_key']
except KeyError:
    age = self.request.session.get_expiry_age()
    if age > set_age:
        #redirect to login page
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.