20

Authentication BackendDjango はデフォルトでユーザー名を大文字と小文字を区別するように実装していますが、認証のために、認証中に大文字と小文字を区別しないユーザー名を処理するために独自に作成しました。

に示すように: http://blog.shopfiber.com/?p=220

さて、問題は次のとおりです。

いくつかのスティングと比較して、さまざまなビューとユーティリティメソッドがありますusername

すなわち

request.user.username == username_from_some_other_system_as_str

ここで、ユーザー名が次のyugal場合:

request.user.username == 'Yugal' # Returns False

今、それは戻るはずTrueです [私が達成したかったこと]

そのために、私は何C++日も覚えていますOperator Overloading。しかし、 djangoに対して単純にそれを行うのauth userは良い考えではないと思います。また、オーバーロードにより、フィールドだけでなくクラス全体で大文字と小文字が区別されなくなります。auth userdjango==username

usernameでは、全体を比較した場合でも、この大文字と小文字を区別しない方法についてどうすればよいでしょうか。

ノート:

  • 常に小文字のユーザー名を返すメソッドを作成するget_usernameことはできません。これを使用するには、すべてのコードをリファクタリングする必要があるためです。コードに対して一度だけ実行できますが、サードパーティの django アプリを使用している場合は実行できません。

  • 可能であることはわかっuser.username.lower() = something.lower()ていますが、バグが発生しやすく、マルチ開発者のセットアップで頻繁に使用されるものの書き込みソリューションではありません。

  • SomeModel.objects.filter(username__iexact=username)可能な限りを使用しました。しかし、それでもシステムは、知らない開発者によるミスに対して脆弱なままです。

======================================

概念的に解決策を考え出しましたが、機能させることができませんでした (ヘルプ):

####### Custom CharField for username case-insensitivity #######
from django.db.models.fields import CharField
class iUnicode:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        if isinstance(other, str) or isinstance(other, unicode):
            return self.value.lower() == other.lower()
        if isinstance(other, self.__class__):
            return other == self.value

    def __unicode__(self):
        return unicode(self.value)
    def __str__(self):
        return self.__unicode__()


class UsernameCharField(CharField):
    def to_python(self, value):  # Its not getting called
        unicode_val = super(CharField, self).to_python(value)
        return iUnicode(unicode_val)

if User._meta.local_fields[1].name == 'username':
    User._meta.local_fields[1] = UsernameCharField(max_length=30)
    User._meta.local_fields[1].model = User
################################################################

to_pythonデータベースから受け取った値をunicodepythonに変換するために使用されると思います。しかし、私to_pythonは呼ばれていないと思います。

これにより、サードパーティのアプリで大文字と小文字が区別されなくなり、リファクタリングが不要になります。Userコアにパッチを適用します。__init__.pyこれを最初のに追加しますINSTALLED_APP

私は何を間違っていますか?

4

7 に答える 7

36

Django 1.5 の時点で、ユーザー名の大文字と小文字を区別しないようにするのは簡単です:

class MyUserManager(BaseUserManager):
    def get_by_natural_key(self, username):
        return self.get(username__iexact=username)

ソース: 12

于 2015-10-31T20:29:34.770 に答える
6

登録とログインのプロセスでいくつかの行を変更しましたが、うまくいくようです。私のソリューションでは、ユーザーが登録時に書いたようにユーザー名が引き続き表示されますが、他のユーザーが別の方法で書かれた同じユーザー名を使用することはできません。また、ユーザーは大文字と小文字を区別するユーザー名を書くことを気にせずにログインできます。

大文字と小文字を区別しないユーザー名を検索するように登録フォームを変更しました。

これは、ユーザー名の検証からの行です。このユーザー名でユーザーを検索します。

User._default_manager.get(username__iexact=username)

次に、ユーザーが大文字と小文字を区別しないユーザー名でログインできるようにする必要がありました。

私のログインビューから:

username = request.POST['username']
password = request.POST['password']
caseSensitiveUsername = username
try:
  findUser = User._default_manager.get(username__iexact=username)
except User.DoesNotExist:
  findUser = None
if findUser is not None:
  caseSensitiveUsername = findUser.get_username
user = auth.authenticate(username=caseSensitiveUsername, password=password)
于 2015-02-22T14:03:42.813 に答える
2

大文字と小文字を区別しないユーザー名を使用する最も簡単な方法は、デフォルトから継承してメソッドModelBackendをオーバーライドauthenticateすることです。

exceptブロック内で実行していることに注意してくださいUserModel().set_password(password)。これにより、ハッシャーの作業時間が短縮されます。バグレポートを修正しました

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model

from users.models import User

class CaseInsensitiveModelBackend(ModelBackend):
    def authenticate(self, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
            d = {'%s__iexact'%UserModel.USERNAME_FIELD: username}
            user = UserModel.objects.get(**d)
            if user.check_password(password):
                return user
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (#20760).
            UserModel().set_password(password)

        return None

AUTHENTICATION_BACKENDSそして、このバックエンドをsettings.pyに追加します

AUTHENTICATION_BACKENDS = (
    'sdcpy.backends.CaseInsensitiveModelBackend', # inherits from 'django.contrib.auth.backends.ModelBackend'
)
于 2015-02-02T13:59:26.347 に答える
0

これを行うには、比較的クリーンな方法があります。

# Case-insensitive django authentication, modified from
# http://justcramer.com/2008/08/23/logging-in-with-email-addresses-in-django/
# See also https://github.com/dabapps/django-email-as-username
# And https://docs.djangoproject.com/en/dev/topics/auth/customizing/#auth-custom-user
from django.contrib.auth.models     import User

class EmailOrUsernameModelBackend(object):
    def authenticate(self, username=None, password=None):
        username = username.lower()     # Force all usernames & email to all lower case
        if '@' in username:
            kwargs = {'email': username}
        else:
            kwargs = {'username': username}
        try:
            user = User.objects.get(**kwargs)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

def my_password_reset(request, **kwargs):
    # Override django.contrib.auth.views.password_reset not needed because django does
    # SELECT FROM "auth_user" WHERE UPPER("auth_user"."email"::text) = UPPER(E'xxx@emaple.com')
    # But note you may want to manually create an UPPER index in the database for speed.
    return password_reset(request, **kwargs)

次に設定

AUTHENTICATION_BACKENDS = (
    'obviously.backends.EmailOrUsernameModelBackend',
    'django.contrib.auth.backends.ModelBackend',
)

また、登録ワークフローでユーザー名を小文字にする必要があります

これはすべて正常に機能しますが、ユーザーによって指定された大文字と小文字が保持されず、データベースでの検索も効率的ではありません。デフォルトの django の動作は設計によるものです。https: //code.djangoproject.com/ticket/2273 を参照してください。

于 2013-09-11T02:39:38.927 に答える
0

このモンキー パッチは悪い考えのように見えます。将来、いくつかの問題に直面することは間違いありません (Django は舞台裏で多くのことを行っています)。アプリの再設計を強くお勧めします。

ただし、次のことを試すことができます(iUnicodeクラスを使用):

def new_getattribute( self, name ):
    val = object.__getattribute__( self, name )
    if name == "username":
        val = iUnicode( val )
    return val

User.__getattribute__ = new_getattr

今、私はこれがうまくいくと 100% 確信しているわけではありません。:)

于 2012-11-02T15:55:06.630 に答える