web-dev-qa-db-ja.com

特定のユーザーのDjangoセッションを検索する方法は?

私は、Djangoおよびスタンドアロンアプリケーションからデータベースにアクセスするアプリケーションを作成しています。両方ともセッションの検証を行う必要があり、セッションは両方で同じでなければなりません。 Djangoには認証/セッション検証が組み込まれています。これは私が使用しているものです。次に、スタンドアロンアプリケーションで同じセッションを再利用する方法を理解する必要があります。

私の質問は、特定のユーザーのsession_keyを検索するにはどうすればよいですか?

見た目から、auth_userとDjango_sessionを結びつけるものは何もありません

51

_Django_session_テーブルを変更して明示的な_user_id_を追加すると、作業が非常に簡単になります。あなたがそれ(または類似の何か)を行うと仮定して、ここにあなたの好みに合わせて物事を変更する4つのアプローチがあります:

_Django.contrib.session_コードをフォークします。私が知っている、私は知っている、それは提案するのは恐ろしいことです。しかし、すべてのバックエンドを含み、テストを差し引いた500行のみです。ハッキングするのはかなり簡単です。これは、真剣な再配置を行う場合にのみ最適なルートです。

フォークしたくない場合は、_Session.post_save_シグナルに接続して、そこを変更することができます。

または、MonkeyPatch contrib.session.models.Session.save()を使用することもできます。既存のメソッドをラップ(または新しいメソッドを作成)し、必要な値をブレイクアウト/合成し、それらを新しいフィールドに格納してから、super(Session, self).save()を実行します。

これを行うもう1つの方法は、settings.pyファイルのSessionMiddlewareの前と後の2つ(はい、2つ)のミドルウェアクラスを配置することです。これはミドルウェアの処理方法が原因です。 SessionMiddlewareの後にリストされているものは、インバウンド要求で、セッションがすでにアタッチされている要求を受け取ります。前にリストしたものは、応答の処理やセッションの変更/再保存を行うことができます。

この最後の手法のバリエーションを使用して、検索エンジンスパイダー用の疑似セッションを作成し、通常はメンバー専用の素材への特別なアクセスを提供しました。また、REFERERフィールドが関連する検索エンジンからのインバウンドリンクを検出し、ユーザーにその1つの記事への完全なアクセス権を付与します。

更新:

私の答えは今ではかなり古いですが、それでもほとんど正しいです。この問題に対するさらに別のアプローチについては、以下の@Gavin_Ballardのより最近の回答(2014年9月29日)を参照してください。

24
Peter Rowell

この回答は元の質問から5年後に投稿されていますが、このSOスレッドは、この問題の解決策を検索したときのGoogleの上位の結果の1つです(それでもまだサポートされていないものです) Djangoですぐに使用できます)。

次のような追加のUserSessionモデルを使用してユーザーをセッションにマッピングする、ログインしたユーザーセッションのみに関係するユースケースの代替ソリューションがあります。

from Django.conf import settings
from Django.db import models
from Django.contrib.sessions.models import Session

class UserSession(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    session = models.ForeignKey(Session)  

その後、ユーザーがログインするたびに、新しいUserSessionインスタンスを保存するだけです。

from Django.contrib.auth.signals import user_logged_in

def user_logged_in_handler(sender, request, user, **kwargs):
    UserSession.objects.get_or_create(user = user, session_id = request.session.session_key)

user_logged_in.connect(user_logged_in_handler)

そして最後に、特定のユーザーのセッションをリスト(および場合によってはクリア)したい場合は、次のようにします。

from .models import UserSession

def delete_user_sessions(user):
    user_sessions = UserSession.objects.filter(user = user)
    for user_session in user_sessions:
        user_session.session.delete()

詳細は、私が ブログ投稿 で説明しています。

44
Gavin Ballard

すべてのセッションが必ずしも認証されたユーザーに関連付けられているわけではないため、これはやや難しいです。 Djangoのセッションフレームワークは匿名セッションもサポートしており、ログインしているかどうかに関係なく、サイトにアクセスした人は誰でもセッションを利用できます。

これは、セッションオブジェクト自体がシリアル化されているという事実により、さらにトリッキーになっています。Djangoには、格納するデータを正確に知る方法がないため、セッションデータのディクショナリをシリアル化するだけです。文字列(Pythonの標準の「pickle」モジュールを使用)およびそれをデータベースに格納します。

セッションキー(ユーザーのブラウザからcookie値 "sessionid"として送信される)がある場合、データを取得する最も簡単な方法は、そのキーを使用してセッションのセッションテーブルをクエリすることです。オブジェクト。次に、そのオブジェクトの「get_decoded()」メソッドを呼び出して、セッションデータの辞書を取得できます。 Djangoを使用していない場合は、ソースコード(Django/contrib/sessions/models.py)を見て、セッションデータがどのようにデシリアライズされるかを確認できます。

ただし、ユーザーIDがある場合は、すべてのSessionオブジェクトをループ処理し、それぞれを逆シリアル化して、「_ auth_user_id」という名前のキーがあり、そのキーの値がユーザーIDであるオブジェクトを探します。 。

28
James Bennett

このコードスニペットを見つけました

from Django.contrib.sessions.models import Session
from Django.contrib.auth.models import User

session_key = '8cae76c505f15432b48c8292a7dd0e54'

session = Session.objects.get(session_key=session_key)
uid = session.get_decoded().get('_auth_user_id')
user = User.objects.get(pk=uid)

print user.username, user.get_full_name(), user.email

ここ http://scottbarnham.com/blog/2008/12/04/get-user-from-session-key-in-Django/

まだ確認していませんが、かなり簡単に見えます。

26
michael

ピーター・ローウェル、回答ありがとうございます。それは途方もない助けでした。これは私がそれを機能させるためにやったことです。 djang.contrib.sessionsの1つのファイルを変更するだけで済みました。

Django/contrib/sessions/models.pyで、user_idをテーブルに追加します(手動でDBテーブルに追加するか、テーブルを削除してmanage.py syncdbを実行します)。

class Session(models.Model):

    ...

    user_id = models.IntegerField(_('user_id'), null=True)

    ...

    def save(self, *args, **kwargs):
        user_id = self.get_decoded().get('_auth_user_id')
        if ( user_id != None ):
            self.user_id = user_id

        # Call the "real" save() method.
        super(Session, self).save(*args, **kwargs)

ログインを行うビューで(Djangoのベースログインを使用する場合は、それを上書きする必要があります)

# On login, destroy all prev sessions
        # This disallows multiple logins from different browsers
        dbSessions = Session.objects.filter( user_id = request.user.id )
        for index, dbSession in enumerate( dbSessions ):
            if ( dbSession.session_key != request.session.session_key ):
                dbSession.delete()

これでうまくいきました。

7
Joe

スパマーを追い出したかったので、この問題に遭遇しました。アカウントを「非アクティブ」に設定するだけでは不十分なようです。これは、以前のセッションに引き続き参加できるためです。だから-特定のユーザーのセッションを削除する方法、または特定のユーザーのセッションを意図的に期限切れにする方法は?

答えはlast_loginフィールドは、セッションが無効にされた時間を追跡し、expire_dateは2週間後です。これにより、セッションテーブルで便利なフィルターを実行できます。

from Django.contrib.sessions.models import Session
from Django.contrib.auth.models import User
from datetime import datetime
from dateutil.relativedelta import relativedelta

baduser = User.objects.get(username="whoever")     
two_weeks = relativedelta(weeks=2)
two_hours = relativedelta(hours=2)
expiry = baduser.last_login + two_weeks
sessions = Session.objects.filter(
    expire_date__gt=expiry - two_hours,
    expire_date__lt=expiry + two_hours
) 
print sessions.count() # hopefully a manageable number

for s in sessions:
    if s.get_decoded().get('_auth_user_id') == baduser.id:
        print(s)
        s.delete()
6
hwjp