ハロルドの答えはこの特定のケースで機能しますが、少なくとも2つの重要な問題があります。
- このソリューションは、データベースセッションエンジンでのみ使用できます。他の状況(キャッシュ、ファイル、Cookie)では、
Session
モデルは使用されません。
- データベース内のセッションとユーザーの数が増えると、これは非常に非効率的になります。
これらの問題を解決するには、問題に対して別のアプローチを取ることをお勧めします。アイデアは、ユーザーが特定のセッションにログインした日付と、ユーザーに最後にログアウトを要求した日付をどこかに保存することです。
その後、誰かがサイトにアクセスするたびに、ログイン日がログアウト日よりも短い場合は、ユーザーを強制的にログアウトできます。ダンが言ったように、ユーザーをすぐにログアウトすることと、サイトへの次のリクエストでログアウトすることの間に実際的な違いはありません。
それでは、django 1.3b1について、このソリューションの可能な実装を見てみましょう。3つのステップで:
1.最終ログイン日をセッションに保存します
幸い、Django認証システムは。と呼ばれるシグナルuser_logged_in
を公開します。そのシグナルを登録し、セッションに現在の日付を保存するだけです。あなたの下部に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.ユーザーの強制ログアウトをリクエストします
モデルにフィールドとメソッドを追加するだけですUser
。これを実現する方法は複数あり(ユーザープロファイル、モデルの継承など)、それぞれ長所と短所があります。
簡単にするために、ここではモデルの継承を使用します。このソリューションを使用する場合は、カスタム認証バックエンドを作成することを忘れないでください。
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()
次に、ユーザーjohndoe
のログアウトを強制する場合は、次のことを行う必要があります。
from myapp.models import MyUser
MyUser.objects.get(username='johndoe').force_logout()
3.アクセスチェックを実装します
ここでの最善の方法は、ダンが提案したようにミドルウェアを使用することです。このミドルウェアはにアクセスするので、設定の後request.user
に置く必要があります。 'django.contrib.auth.middleware.AuthenticationMiddleware'
MIDDLEWARE_CLASSES
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)
それはそれをする必要があります。
ノート
- ユーザーのために追加のフィールドを保存することのパフォーマンスへの影響に注意してください。モデルの継承を使用すると、が追加され
JOIN
ます。ユーザープロファイルを使用すると、クエリが追加されます。を直接変更することUser
は、パフォーマンスの面で最善の方法ですが、それでも厄介なトピックです。
そのソリューションを既存のサイトに展開する場合、'LAST_LOGIN_DATE'
キーを持たない既存のセッションで問題が発生する可能性があります。その場合に対処するためにミドルウェアコードを少し適応させることができます:
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)
django 1.2.xでは、user_logged_in
シグナルはありません。login
関数のオーバーライドにフォールバックします。
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()