82

私のDjangoアプリでは、特定の条件下で、ユーザーがユーザー名で強制的にログアウトできるようにしたいと考えています。現在ログインしているユーザーとは限りませんが、別のユーザーです。そのため、私のビューのリクエスト メソッドには、ログアウトしたいユーザーに関するセッション情報がありません。

私はdjango.authとauthに精通しています。logout メソッドに似ていますが、リクエストを引数として取ります。ユーザー名しかない場合、ユーザーをログアウトするための「Django-way」はありますか? または、独自のログアウト SQL をロールバックする必要がありますか?

4

10 に答える 10

89

アップデート:

Django 1.7 以降、パスワードが変更されると、ユーザーは自動的にログアウトされます。要求ごとに、現在のパスワード ハッシュがセッションに保存されている値と比較され、一致しない場合、ユーザーはログアウトされます。

したがって、単純なパスワードの更新は、ユーザーをログアウトさせる効果があります。次に、ログイン用のアカウントを無効にするか、パスワード リセット機能を使用して新しいパスワードを設定し、再度ログインするようにアドバイスします。

オリジナル:

Django でこれを行うための認可された方法はまだないと思います。

ユーザー ID はセッション オブジェクトに格納されますが、エンコードされます。残念ながら、それはすべてのセッションを反復処理し、デコードして比較する必要があることを意味します...

2 つのステップ:

まず、ターゲット ユーザーのセッション オブジェクトを削除します。複数のコンピューターからログインすると、複数のセッション オブジェクトが存在します。

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

# grab the user in question 
user = User.objects.get(username='johndoe')

[s.delete() for s in Session.objects.all() if s.get_decoded().get('_auth_user_id') == user.id]

次に、必要に応じて、それらをロックアウトします....

user.is_active = False
user.save()
于 2009-06-05T04:54:13.017 に答える
66

ハロルドの答えはこの特定のケースで機能しますが、少なくとも2つの重要な問題があります。

  1. このソリューションは、データベースセッションエンジンでのみ使用できます。他の状況(キャッシュ、ファイル、Cookie)では、Sessionモデルは使用されません。
  2. データベース内のセッションとユーザーの数が増えると、これは非常に非効率的になります。

これらの問題を解決するには、問題に対して別のアプローチを取ることをお勧めします。アイデアは、ユーザーが特定のセッションにログインした日付と、ユーザーに最後にログアウトを要求した日付をどこかに保存することです。

その後、誰かがサイトにアクセスするたびに、ログイン日がログアウト日よりも短い場合は、ユーザーを強制的にログアウトできます。ダンが言ったように、ユーザーをすぐにログアウトすることと、サイトへの次のリクエストでログアウトすることの間に実際的な違いはありません。

それでは、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()
    
于 2011-02-20T07:16:06.290 に答える
51

アプリで同様のものが必要でした。私の場合、ユーザーが非アクティブに設定されている場合、ユーザーが既にログインしているかどうかを確認して、ログアウトしてサイトを引き続き使用できないようにしたいと考えました。この投稿を読んだ後、次の解決策にたどり着きました。

from django.contrib.auth import logout

class ActiveUserMiddleware(object):
    def process_request(self, request):
        if not request.user.is_authenticated:
            return
        if not request.user.is_active:
           logout(request)

このミドルウェアを設定に追加するだけで、すぐに使用できます。パスワードを変更する場合、userprofile モデルに新しいフィールドを導入して、ユーザーを強制的にログアウトさせ、上記の is_active の代わりにフィールドの値を確認し、ユーザーがログインしたときにフィールドの設定を解除することもできます。後者は、 Django のuser_logged_inシグナルで実行できます。

于 2011-10-24T06:07:25.377 に答える
7

おそらく、ログアウトを強制されたユーザーのリストを参照するちょっとしたミドルウェアです。次にユーザーが何かをしようとすると、ログアウトしたり、リダイレクトしたりします。

もちろん、すぐにログアウトする必要がある場合を除きます。しかし、繰り返しになりますが、彼らは次にリクエストをしようとするまで気付かないので、上記の解決策はうまくいくかもしれません.

于 2009-06-09T23:24:30.393 に答える
6

これは、バロンの質問への回答です。

はい、約14万回のセッションを繰り返すことで、ハロルドの答えが思ったほど速くない理由がわかります。

私がお勧めする方法は、2つのプロパティのみがオブジェクトへUserの外部キーであるモデルを追加することです。Session次に、このモデルを現在のユーザーセッションで最新の状態に保つミドルウェアを追加します。私は以前にこの種のセットアップを使用しました。私の場合、phpBB用のこのシングルサインオンシステムsessionprofileからモジュールを借りました(「django / sessionprofile」フォルダーのソースコードを参照)。これは(私が思うに)あなたのニーズに合うでしょう。

最終的には、次のようなコードのどこかにある管理機能があります(sessionprofile上記のリンク先のモジュールと同じコード名とレイアウトを想定しています)。

from sessionprofile.models import SessionProfile
from django.contrib.auth.models import User

# Find all SessionProfile objects corresponding to a given username
sessionProfiles = SessionProfile.objects.filter(user__username__exact='johndoe')

# Delete all corresponding sessions
[sp.session.delete() for sp in sessionProfiles]

(これはオブジェクトも削除すると思います。SessionProfile私が思い出したように、aによって参照されるオブジェクトForeignKeyが削除されたときのDjangoのデフォルトの動作は、それをカスケードし、を含むオブジェクトも削除することForeignKeyですが、そうでない場合は、sessionProfiles終わったときの内容。)

于 2011-02-18T08:33:21.287 に答える
2

Tony Abou-Assaleh として、非アクティブに設定されたユーザーをログアウトする必要もあったため、彼のソリューションを実装することから始めました。しばらくして、ミドルウェアが (ユーザーがブロックされているかどうかを確認するために) すべてのリクエストに対して DB クエリを強制しているため、ログインを必要としないページのパフォーマンスが低下していることがわかりました。

私はカスタムユーザーオブジェクトとDjango> = 1.7を持っているのでget_session_auth_hash、ユーザーが非アクティブなときにセッションを無効にする機能をオーバーライドすることになりました。可能な実装は次のとおりです。

def get_session_auth_hash(self):
    if not self.is_active:
        return "inactive"
    return super(MyCustomUser, self).get_session_auth_hash()

これが機能するためにdjango.contrib.auth.middleware.SessionAuthenticationMiddlewareは、settings.MIDDLEWARE_CLASSES

于 2015-08-31T15:25:40.590 に答える
0

from django.contrib.sessions.models import セッション

ユーザー セッションの削除

[s.delete() for s in Session.objects.all() if s.get_decoded().get('_auth_user_hash') == user.get_session_auth_hash()]
于 2016-06-03T09:29:05.720 に答える
-5

私でさえこの問題に直面しました。インドからのスパマーは、愛の解決策を求めてババとモルヴィについて投稿し続けています.

私がしたことは、投稿時にこのコードを挿入したところです:

if request.user.is_active==False:
            return HttpResponse('You are banned on the site for spaming.')
于 2017-08-27T12:06:29.297 に答える