Mặc dù câu trả lời của Harold hoạt động trong trường hợp cụ thể này, tôi có thể thấy ít nhất hai vấn đề quan trọng với nó:
- Giải pháp này chỉ có thể được sử dụng với một công cụ phiên cơ sở dữ liệu . Trong các tình huống khác (bộ nhớ cache, tệp, cookie),
Session
mô hình sẽ không được sử dụng.
- Khi số lượng phiên và người dùng trong cơ sở dữ liệu tăng lên, điều này trở nên khá kém hiệu quả.
Để giải quyết những vấn đề đó, tôi khuyên bạn nên thực hiện một cách tiếp cận vấn đề khác. Ý tưởng là lưu trữ ở đâu đó ngày người dùng đăng nhập trong một phiên nhất định và lần cuối cùng bạn yêu cầu người dùng đăng xuất.
Sau đó, bất cứ khi nào ai đó truy cập trang web của bạn, nếu ngày đăng nhập thấp hơn ngày đăng xuất, bạn có thể buộc đăng xuất người dùng. Như dan đã nói, không có sự khác biệt thực tế nào giữa việc đăng xuất người dùng ngay lập tức hoặc theo yêu cầu tiếp theo của anh ta đối với trang web của bạn.
Bây giờ, chúng ta hãy xem một triển khai khả thi của giải pháp này, cho django 1.3b1 . Trong ba bước:
1. lưu trữ trong phiên ngày đăng nhập cuối cùng
May mắn thay, hệ thống xác thực Django để lộ một tín hiệu được gọi user_logged_in
. Bạn chỉ cần đăng ký các tín hiệu đó và lưu ngày hiện tại trong phiên. Ở cuối của bạn models.py
:
from django.contrib.auth.signals import user_logged_in
from datetime import datetime
def update_session_last_login(sender, user=user, request=request, **kwargs):
if request:
request.session['LAST_LOGIN_DATE'] = datetime.now()
user_logged_in.connect(update_session_last_login)
2. yêu cầu buộc đăng xuất cho người dùng
Chúng ta chỉ cần thêm một trường và một phương thức vào User
mô hình. Có nhiều cách để đạt được điều đó ( hồ sơ người dùng , kế thừa mô hình , v.v.), mỗi cách đều có ưu và nhược điểm.
Để đơn giản, tôi sẽ sử dụng kế thừa mô hình ở đây, nếu bạn sử dụng giải pháp này, đừng quên viết một chương trình phụ trợ xác thực tùy chỉnh .
from django.contrib.auth.models import User
from django.db import models
from datetime import datetime
class MyUser(User):
force_logout_date = models.DateTimeField(null=True, blank=True)
def force_logout(self):
self.force_logout_date = datetime.now()
self.save()
Sau đó, nếu bạn muốn buộc đăng xuất cho người dùng johndoe
, bạn chỉ cần:
from myapp.models import MyUser
MyUser.objects.get(username='johndoe').force_logout()
3. thực hiện kiểm tra quyền truy cập
Cách tốt nhất ở đây là sử dụng một phần mềm trung gian như dan đề xuất. Phần mềm trung gian này sẽ truy cập request.user
, vì vậy bạn cần đặt nó sau 'django.contrib.auth.middleware.AuthenticationMiddleware'
trong MIDDLEWARE_CLASSES
cài đặt của mình .
from django.contrib.auth import logout
class ForceLogoutMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated() and request.user.force_logout_date and \
request.session['LAST_LOGIN_DATE'] < request.user.force_logout_date:
logout(request)
Nên làm vậy.
Ghi chú
- Lưu ý về hiệu suất của việc lưu trữ thêm một trường cho người dùng của bạn. Sử dụng kế thừa mô hình sẽ bổ sung thêm
JOIN
. Sử dụng hồ sơ người dùng sẽ thêm một truy vấn bổ sung. Sửa đổi trực tiếp User
là cách tốt nhất để thực hiện một cách khôn ngoan, nhưng nó vẫn là một chủ đề khó hiểu .
Nếu bạn triển khai giải pháp đó trên một trang hiện có, có thể bạn sẽ gặp một số rắc rối với các phiên hiện có, phiên này sẽ không có 'LAST_LOGIN_DATE'
khóa. Bạn có thể điều chỉnh một chút mã phần mềm trung gian để đối phó với trường hợp đó:
from django.contrib.auth import logout
class ForceLogoutMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated() and request.user.force_logout_date and \
( 'LAST_LOGIN_DATE' not in request.session or \
request.session['LAST_LOGIN_DATE'] < request.user.force_logout_date ):
logout(request)
Trong django 1.2.x, không có user_logged_in
tín hiệu. Quay lại ghi đè login
hàm:
from django.contrib.auth import login as dj_login
from datetime import datetime
def login(request, user):
dj_login(request, user)
request.session['LAST_LOGIN_DATE'] = datetime.now()