2012-01-19 23 views
21

ログインしているユーザーにアクティブなセッションが1つしかないように制限したい、つまりユーザーが新しいセッションIDでログインする場合、古いセッションを終了する必要があります。 私はSOすでに上で多くの援助が見つかりました:私は...、これまでのところ...余分なチェックのビットで、とても良いDjangoアプリケーションでアクティブなセッションを1つだけ許可する

class OnlyOneUserMiddleware(object): 
""" 
Middleware to ensure that a logged-in user only has one session active. 
Will kick out any previous session. 
""" 
def process_request(self, request): 
    if request.user.is_authenticated(): 
     try: 
      cur_session_key = request.user.get_profile().session_key 
      if cur_session_key and cur_session_key != request.session.session_key: 
       # Default handling... kick the old session... 
       Session.objects.get(session_key=cur_session_key).delete() 
      if not cur_session_key or cur_session_key != request.session.session_key: 
       p = request.user.get_profile() 
       p.session_key = request.session.session_key 
       p.save() 
     except ObjectDoesNotExist: 
      pass 

をミドルウェア・ソリューションを実現し herehere

Djangoのdevサーバ(manage.py runserver)はすべて正常に動作し、古いセッションを起動します...

...しかし、Apache(mod_wsgi)を使用すると動作しません!

私はこれについての情報を見つけることを試みましたが、今のところ...

運が、私が見つけた最も近いthisありませんが、それは反対か」の問題のようなものです...

ご協力いただければ幸いです。

編集:私はセッションを削除する前に、デバッグプリントを追加... は、ここでは、Apacheのerror.logファイルからの抜粋です:

[Fri Jan 20 09:56:50 2012] [error] old key = f42885ccb7f33b6afcb2c18fca14f44a 
[Fri Jan 20 09:56:50 2012] [error] new key = ce4cfb672e6025edb8ffcd0cf2b4b8d1 
[Fri Jan 20 09:57:14 2012] [error] old key = f42885ccb7f33b6afcb2c18fca14f44a 
[Fri Jan 20 09:57:14 2012] [error] new key = 0815c56241ac21cf4b14b326f0aa7e24 

最初の二つの嘘は、私が最初のセッション(Firefoxで入力されたときからのもの)

最後の二つは、私は2番目のセッション(クロム)

に入ったときからのもの...それは...古いセッションレコードが削除されないことが判明します?私はdevserverで行ったように、私は正確に同じのPostgreSQLインスタンス対実行しているよ

...

EDIT2:これは、新しいSESSION_KEYがなかったとき、それが失敗した...私のコードにバグがあったことが判明しました

がここに固定されたコードだ...セッションで見つかった... try..exceptが正しい場所に今ある

class OnlyOneUserMiddleware(object): 
    """ 
    Middleware to ensure that a logged-in user only has one session active. 
    Will kick out any previous session. 
    """ 
    def process_request(self, request): 
     if request.user.is_authenticated(): 
      cur_session_key = request.user.get_profile().session_key 
      if cur_session_key and cur_session_key != request.session.session_key: 
       # Default handling... kick the old session... 
       try: 
        s = Session.objects.get(session_key=cur_session_key) 
        s.delete() 
       except ObjectDoesNotExist: 
        pass 
      if not cur_session_key or cur_session_key != request.session.session_key: 
       p = request.user.get_profile() 
       p.session_key = request.session.session_key 
       p.save() 
+4

「うまくいきません」と言うと、正確には機能していないのは何ですか?あなたはまだDBの古いセッションを参照してください? 'Session'削除の直前にprint/logging呼び出しを置くと' mod_wsgi'で実行されたことが分かりますか? – AdamKG

+0

@AdamKG:正しい方向に私を指してくれてありがとう! –

+0

セッションエンジンがcache_dbの場合、セッションキーを手動でキャッシュから削除する必要があると思います。 – Wesley

答えて

1

推奨されていないがあなたは常にこの方法を使用することができ、それが動作します。

my_old_sessions = Session.objects.all() 
for row in my_old_sessions: 
    if row.get_decoded().get("_username") == request.user.username: 
     row.delete() 

上記のコードは、ユーザーを認証する直前のlogin()関数で実装します。

request.session["_username"] = request.user.username 

をあなただけのすべてのデータベースを空にすることを忘れないでください、このアプローチを使用する場合:あなたは、次のようにユーザーが自分のセッションにユーザー名保存するログイン()関数法を持っている場合はもちろんの

これはのみ動作しますKeyLookUpエラーが発生するため、これらの変更を行った後にサーバーを実行する前にセッションを更新してください。

+0

_usernameは、セッションオブジェクトのget_decoded()(Django 1.8)には存在しません。しかし、user_idは 'row.get_decoded()。get(" _ auth_user_id ")== request.user.pk'のように動作します。 – guival

1

実際には、似たような質問がたくさんありますが、ここに私の解決策があります。

ユーザーがログインすると、アクティブなセッションがすべて終了し、同じセッションのセッションが削除されます。user.id小規模なウェブサイトの場合、これはうまくいくはずです。

# __init__.py 
# Logs user out from all other sessions on login, django 1.8 

from django.contrib.sessions.models import Session 
from django.contrib.auth.signals import user_logged_in 
from django.db.models import Q 
from django.utils import timezone 

def limit_sessions(sender, user, request, **kwargs): 
    # this will be slow for sites with LOTS of active users 

    for session in Session.objects.filter(
     ~Q(session_key = request.session.session_key), 
     expire_date__gte = timezone.now() 
    ): 
     data = session.get_decoded() 
     if data.get('_auth_user_id', None) == str(user.id): 
      # found duplicate session, expire it 
      session.expire_date = timezone.now() 
      session.save() 

    return 

user_logged_in.connect(limit_sessions) 
+0

2つの方法のパフォーマンスを比較しましたか?私は、信号とミドルウェアを経由する方法を意味します。ミドルウェアを使用する場合は、すべてのリクエストがhandle_requestを経由する必要があります。シグナルを使用すると、ログインイベントだけが関数にヒットしますが、セッションテーブルを反復するので、パフォーマンスについて考えてみてください。 – Wesley

+0

「小さいウェブサイト」と言っていました:) - あなたはOPのようなキーを保存しますが、ログイン時にチェックしてください。よりパフォーマンスの高いソリューションをお探しください – MarZab

+0

ええ、私はあなたが小さなサイトについて言及しているのを見ています:-)私は大規模なサイトで何が良いかを知りたいです:-) – Wesley

0

何とかdjango.contrib.authシグナルがここで役立つと感じました。ログイン時に、古いユーザーセッションを無効にします。

+0

すでにユーザーデータベースで作業している場合は、これを実行するにはすべてのユーザーが最初にログアウトする必要があります。 – guival

関連する問題