Djangoでユーザーがアイドルタイムアウトになったときを確認するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/644471

  •  22-07-2019
  •  | 
  •  

質問

ユーザーがDjangoアプリケーションでアイドルタイムアウトを経験したときに監査したい。つまり、ユーザーのセッションCookieの有効期限がsettings.pyで見つかったSESSION_COOKIE_AGEを超えると、ユーザーはログインページにリダイレクトされます。それが発生すると、監査も発生するはずです。 「監査」とは、person.auditテーブルにレコードを書き込むことを意味します。

現在、これらのイベントをキャプチャするためにいくつかのミドルウェアを構成しています。残念ながら、ユーザーがログインページにリダイレクトされたときにDjangoが新しいCookieを生成するため、ユーザーがアイドルタイムアウトまたはその他のイベントによってログインページに移動したかどうかを判断できません。

伝えることができることから、「django_session」で作業する必要があります。表。ただし、リダイレクトが発生するとCookieのsessionid値がリセットされるため、このテーブルのレコードをそのユーザーに関連付けることはできません。

このジレンマに遭遇したのは私が初めてではないと思います。誰も問題を解決する方法についての洞察を持っていますか?

役に立ちましたか?

解決

更新:

少しテストした後、以下のコードでは質問に答えられないことがわかりました。動作し、シグナルハンドラが呼び出されますが、 prev_session_data が存在する場合、有用な情報は含まれません。

最初に、セッションフレームワークの内部覗き見:

  1. 新しい訪問者がアプリケーションURLを要求すると、新しいセッションが生成されます-この時点では、それらはまだ匿名です( request.user はAnonymousUserのインスタンスです)。
  2. 認証が必要なビューをリクエストすると、ログインビューにリダイレクトされます。
  3. ログインビューが要求されると、ユーザーのセッションにテスト値が設定されます( SessionStore._session )。これにより、現在のセッションで accessed および modified フラグが自動的に設定されます。
  4. 上記のリクエストの応答フェーズ中、 SessionMiddleware は現在のセッションを保存し、 django_session テーブルに新しい Session インスタンスを効果的に作成します( django.contrib.sessions.backends.db が提供するデフォルトのデータベースバックアップセッションを使用している場合)。新しいセッションのIDは、 settings.SESSION_COOKIE_NAME Cookieに保存されます。
  5. ユーザーがユーザー名とパスワードを入力してフォームを送信すると、認証されます。認証が成功すると、 django.contrib.auth login メソッドが呼び出されます。 login は、現在のセッションにユーザーIDが含まれているかどうかを確認します。存在し、IDがログインしているユーザーのIDと同じである場合、セッションデータを保持しながら、 SessionStore.cycle_key を呼び出して新しいセッションキーを作成します。それ以外の場合は、 SessionStore.flush が呼び出され、すべてのデータが削除されて新しいセッションが生成されます。これらのメソッドは両方とも、以前のセッション(匿名ユーザー用)を削除し、 SessionStore.create を呼び出して新しいセッションを作成する必要があります。
  6. この時点で、ユーザーは認証され、新しいセッションがあります。それらのIDは、認証に使用されるバックエンドとともにセッションに保存されます。セッションミドルウェアはこのデータをデータベースに保存し、新しいセッションIDを settings.SESSION_COOKIE_NAME に保存します。

おわかりのように、以前のソリューションの大きな問題は、 create が呼び出されるまでに(ステップ5.)、以前のセッションのIDがなくなってしまうことです。 他の人が指摘しているように、これはセッションCookieの有効期限が切れると、ブラウザによって静かに削除されます。

Alex Gaynorの提案に基づいて、私は別のアプローチを考え出したと思います、それはあなたが求めていることをするようです、それはまだ端の周りで少し荒いです。基本的に、私は2番目の長命の「監査」を使用します。セッションIDをミラーリングするCookie、およびそのCookieの存在を確認するミドルウェア。リクエストの場合:

  • 監査CookieもセッションCookieも存在しない場合、これはおそらく新規ユーザーです
  • 監査Cookieは存在するがセッションCookieは存在しない場合、これはおそらくセッションの有効期限が切れたばかりのユーザーです
  • 両方のCookieが存在し、同じ値を持つ場合、これはアクティブセッションです

これまでのコードは次のとおりです。

sessionaudit.middleware.py

from django.conf import settings
from django.db.models import signals
from django.utils.http import cookie_date
import time

session_expired = signals.Signal(providing_args=['previous_session_key'])

AUDIT_COOKIE_NAME = 'sessionaudit'

class SessionAuditMiddleware(object):
    def process_request(self, request):
        # The 'print' statements are helpful if you're using the development server
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
        audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
        if audit_cookie is None and session_key is None:
            print "** Got new user **"
        elif audit_cookie and session_key is None:
            print "** User session expired, Session ID: %s **" % audit_cookie
            session_expired.send(self.__class__, previous_session_key=audit_cookie)
        elif audit_cookie == session_key:
            print "** User session active, Session ID: %s **" % audit_cookie

    def process_response(self, request, response):
        if request.session.session_key:
            audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
            if audit_cookie != request.session.session_key:
                # New Session ID - update audit cookie:
                max_age = 60 * 60 * 24 * 365  # 1 year
                expires_time = time.time() + max_age
                expires = cookie_date(expires_time)
                response.set_cookie(
                    AUDIT_COOKIE_NAME,
                    request.session.session_key,
                    max_age=max_age,
                    expires=expires,
                    domain=settings.SESSION_COOKIE_DOMAIN,
                    path=settings.SESSION_COOKIE_PATH,
                    secure=settings.SESSION_COOKIE_SECURE or None
                )
        return response

audit.models.py

from django.contrib.sessions.models import Session
from sessionaudit.middleware import session_expired

def audit_session_expire(sender, **kwargs):
    try:
        prev_session = Session.objects.get(session_key=kwargs['previous_session_key'])
        prev_session_data = prev_session.get_decoded()
        user_id = prev_session_data.get('_auth_user_id')
    except Session.DoesNotExist:
        pass

session_expired.connect(audit_session_expire)

settings.py

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'sessionaudit.middleware.SessionAuditMiddleware',
    ...
)

INSTALLED_APPS = (
    ...
    'django.contrib.sessions',
    'audit',
    ...
)

これを使用している場合は、ユーザーがログアウトするときに監査Cookieを明示的に削除するカスタムログアウトビューを実装する必要があります。また、django signed-cookiesミドルウェアを使用することをお勧めします(ただし、おそらく既にそれを行っているのではないでしょうか?)

古い:

yだと思う

他のヒント

SESSION_COOKIE_AGE = 1500#25分

それを設定に入れて、それを処理してセッションを期限切れにする必要があります。

Djangoについては知りませんが、サイトのページへの最終アクセス時刻を保存する非永続的なCookieを作成することはできます(ページの読み込みごとにCookieを更新します)

ログインページで、ユーザーがCookieを持っているかどうかを確認できますが、セッションはありません。そうすれば、ユーザーのセッションがタイムアウトした可能性が高いことがわかります。サイトのページに最後にアクセスした時刻があるため、セッションの期間に基づいて、タイムアウトしたかどうかを計算することもできます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top