Django:用户名和密码用户名不区分大小写匹配 [英] Django : Case insensitive matching of username from auth user?

查看:939
本文介绍了Django:用户名和密码用户名不区分大小写匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Django by-default实现用户名区分大小写,现在用于身份验证我已经编写了自己的身份验证后端,以便在身份验证时处理不区分大小写的用户名。

Django by-default implements username as case sensitive, now for authentication I have written my own Authentication Backend to handle case insensitive usernames while authentication.

如下所示: http://blog.shopfiber.com/?p=220

现在,问题是:

我有各种各样的视图和util方法,比较用户名到一些蜇。

I have various views and util methods which compares username to some stings.

ie

request.user.username == username_from_some_other_system_as_str

现在,如果用户名是 yugal 然后:

Now, if username is yugal then:

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

现在,它应该返回 True [我想要实现]

Now, it should return True [ What I wanted to achieve ]

为了我记得从 C ++ days,运算符重载
但我不认为这样做只是为了django的 auth用户将是一个好主意,因为 auth user django 紧密绑定。
此外,重载 == 将使整个类不区分大小写,而不仅仅是用户名

For that I remember from C++ days, Operator Overloading. But I don't think simply doing that for django's auth user would be a good idea, since auth user is tightly bound with django. Also, overloading == will make it case-insensitive for the whole class not just for the username field.

所以,即使在比较时,我该怎么去讨论这个用户名 case-insensitivity。

So, how should I go about this username case-insensitivity even when compared throughout.

注意:


  • 创建一个 get_username 返回小写用户名的方法是不可能的,因为它需要重新确定所有代码才能使用它。您可以为代码执行一次,但如果您使用第三方django应用程序,则不可能。

  • Creating a get_username method that returns lower-case username always is not possible, since it would require all code to be re-factored to use it. You can do it for your code for once, but not possible if you are using 3rd party django apps.

我知道用户。 username.lower()= something.lower()是可能的,但是容易出错,而不是在多开发人员设置中经常使用的写入解决方案。

I know user.username.lower() = something.lower() is possible but is bug prone and not the write solution for something so often used in a multi-developer setup.

尽可能使用 SomeModel.objects.filter(username__iexact = username)。但是,这仍然使系统容易受到任何不了解的开发人员的错误。

I have used SomeModel.objects.filter(username__iexact=username), wherever possible. But that still leaves the system vulnerable to a mistake by any of un-aware developer.

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

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

在概念上解决了解决方案,但无法使其工作(帮助):

####### 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 用于将从数据库接收的值转换为python中的 unicode 。但是,我想我的 to_python 没有被调用。

I assume to_python is used to convert the value received from database to unicode in python. But, I guess my to_python is not getting called.


这也将确保第三方应用程序不区分大小写,不需要重新分解。它将其核心的用户修补。我将添加到我的第一个 INSTALLED_APP

This will also ensure case-insensitivity in 3rd party apps and would not require any re-factoring. It will patch the User at its core. I will be adding this to __init__.py of my first INSTALLED_APP

我做错了什么?

推荐答案

User 模型进行了如此多的实验和最小化的影响,终于实现了。
[感谢先生。 @freakish 为不同的想法]

With so much experimenting and minimum effect on User model, finally achieved it. [ Thanks to Mr. @freakish for a different thought ]

这是:

############ username case-insensitivity ############
class iunicode(unicode):
    def __init__(self, value):
        super(iunicode, self).__init__(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 custom_getattribute(self, name):
    val = object.__getattribute__(self, name)
    if name == "username":
        val = iunicode(val)
    return val

def auth_user_save(self, *args, **kwargs): # Ensures lowercase usernames
    username = self.username
    if username and type(username) in [unicode, str, iunicode]:
        self.username = username.lower()   # Only lower case allowed
    super(User, self).save(*args, **kwargs)

User.__getattribute__ = custom_getattribute
User.save = MethodType(auth_user_save, None, User)
#####################################################

我测试了它,它按预期工作。 :D

I tested it and it worked as expected. :D

所以,这里是 testcases

from django.test.testcases import TestCase

def create_user(data='testuser'):
    email = '%s@%s.com' % (data, data)
    user = G(User, username=data, email=email, is_active=True)
    user.set_password(data)
    user.save()
    return user

class UsernameCaseInsensitiveTests(TestCase):

    def test_user_create(self):
        testuser = 'testuser'
        user = create_user(testuser)
        # Lowercase
        self.assertEqual(testuser, user.username)
        # Uppercase
        user.username = testuser.upper()
        user.save()
        self.assertEqual(testuser, user.username)

def test_username_eq(self):
    testuser = 'testuser'
    user = create_user(testuser)
    self.assertTrue(isinstance(user.username, iunicode))
    self.assertEqual(user.username, testuser)
    self.assertEqual(user.username, testuser.upper())
    self.assertTrue(user.username == testuser.upper())
    self.assertTrue(testuser.upper() == user.username)
    self.assertTrue(user.username == iunicode(testuser.upper()))



数据库的隐含不区分大小写的查询

Implicit Case-insensitive queries for database

###################### QuerySet #############################
def _filter_or_exclude(self, negate, *args, **kwargs):
    if 'username' in kwargs:
        kwargs['username__iexact'] = kwargs['username']
        del kwargs['username']
    if args or kwargs:
        assert self.query.can_filter(),\
        "Cannot filter a query once a slice has been taken."
    from django.db.models import Q
    clone = self._clone()
    if negate:
        clone.query.add_q(~Q(*args, **kwargs))
    else:
        clone.query.add_q(Q(*args, **kwargs))
    return clone

from django.db.models.query import QuerySet
QuerySet._filter_or_exclude = _filter_or_exclude
#############################################################

这将允许 User.objects.get(username ='yugal')& User.objects.get(username ='YUGAl')产生相同的用户。

This will allow, User.objects.get(username='yugal') & User.objects.get(username='YUGAl') yield the same user.

这篇关于Django:用户名和密码用户名不区分大小写匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆