无法使用自定义用户和 Mezzanine/South 登录到 Django Admin
Posted
技术标签:
【中文标题】无法使用自定义用户和 Mezzanine/South 登录到 Django Admin【英文标题】:Can't login to Django Admin with custom user and Mezzanine/South 【发布时间】:2014-12-13 15:39:12 【问题描述】:我有一个像这样的自定义用户的 django 应用程序:
import ...
logger = logging.getLogger(__name__)
# # Person (representation of people)
class AbstractPerson(models.Model):
"""
ABSTRACT model representing basic information about a person on the platform,
be it a user or a person used in acts he's generating.
"""
MALE = 'M'
FEMALE = 'F'
GIRL = 'G'
FRENCH_TITLES = (
(MALE, 'M.'),
(FEMALE, 'Mme'),
(GIRL, 'Mlle'),
)
date_created = models.DateTimeField(_('date created'),
default=timezone.now,
db_index=True)
title = models.CharField(u'Civilité', max_length=1,
choices=FRENCH_TITLES,
blank=True)
first_name = models.CharField(u'Prénom', max_length=500, blank=True)
last_name = models.CharField(u'Nom', max_length=500, blank=True,
db_index=True)
phone = models.CharField(u'Téléphone', max_length=10, blank=True)
address_1 = models.CharField(u'Adresse', max_length=200, blank=True)
address_2 = models.CharField(u"Complément d'adresse", max_length=200,
blank=True, null=True)
zipcode = models.CharField(u'Code Postal', max_length=10, blank=True)
city = models.CharField(u'Ville', max_length=50, blank=True)
class Meta:
abstract = True
# # Auth
class UserManager(BaseUserManager):
"""Replacement for django auth's UserManager"""
def create_user(self, email, password=None, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('Users must have an email address')
email = UserManager.normalize_email(email)
now = timezone.now()
user = self.model(email=email,
is_staff=False, is_active=True, is_superuser=False,
last_login=now, date_created=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **extra_fields):
u = self.create_user(email, password=password, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u
class User(AbstractPerson, AbstractBaseUser, PermissionsMixin):
"""
Replacement for django.contrib.auth's User.
Gets basic Person information injected from AbstractPerson
"""
# Regular fields
email = models.EmailField(_('email address'), max_length=255,
unique=True, db_index=True)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user '
'can log into this admin site.'))
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether the user '
'should be treated as active. '
'Unselect this instead of '
'deleting accounts.'))
# Compatibility with Mezzanine accounts app
username = models.EmailField(_('username (copy of email address)'),
max_length=255,
unique=True, db_index=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = [] # Nothing required apart from email
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
abstract = False
def save(self, *args, **kwargs):
self.username = self.email
try: kwargs.pop('username')
except KeyError: pass
super(User, self).save(*args, **kwargs)
那么我的设置是:
# Custom user model
AUTH_USER_MODEL = 'useraccount.User'
INSTALLED_APPS = (
'grappelli',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.comments',
'django.contrib.contenttypes',
"django.contrib.redirects",
'django.contrib.sessions',
"django.contrib.sites",
"django.contrib.sitemaps",
'django.contrib.staticfiles',
"storages", # django-storages backend
## Custom user model and such
'useraccount',
## Mezzanine
"mezzanine.boot",
"mezzanine.conf",
"mezzanine.core",
"mezzanine.generic",
#"mezzanine.blog",
"mezzanine.forms",
"mezzanine.pages",
#"mezzanine.galleries",
#"mezzanine.twitter",
#"mezzanine.accounts",
#"mezzanine.mobile",
'south',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
"mezzanine.core.request.CurrentRequestMiddleware",
"mezzanine.core.middleware.RedirectFallbackMiddleware",
"mezzanine.core.middleware.TemplateForDeviceMiddleware",
"mezzanine.core.middleware.TemplateForHostMiddleware",
"mezzanine.core.middleware.AdminLoginInterfaceSelectorMiddleware",
"mezzanine.core.middleware.SitePermissionMiddleware",
# Uncomment the following if using any of the SSL settings:
#"mezzanine.core.middleware.SSLRedirectMiddleware",
"mezzanine.pages.middleware.PageMiddleware",
"mezzanine.core.middleware.FetchFromCacheMiddleware",
)
现在,我已经同步了数据库并创建了一个超级用户。在 shell 中,一切看起来都不错:
In [1]: from useraccount.models import User
In [2]: from django.contrib.auth import authenticate
In [3]: authenticate(username='john', password='secret')
Out[3]: <User: john>
In [4]: u = User.objects.all()[0]
In [5]: u.is_active
Out[5]: True
In [6]: u.is_staff
Out[6]: True
In [7]: u.is_superuser
Out[7]: True
尽管如此,无法连接到管理员...管理员没有说:
Please enter the correct email address and password for a staff account. Note that both fields may be case-sensitive.
但是:
Please correct the error below.
有什么想法吗?
编辑
对不起,我没有说清楚我使用 MezzanineBackend 来验证用户:
AUTHENTICATION_BACKENDS = ("mezzanine.core.auth_backends.MezzanineBackend",)
代码是这样的:
class MezzanineBackend(ModelBackend):
def authenticate(self, **kwargs):
if kwargs:
username = kwargs.pop("username", None)
if username:
username_or_email = Q(username=username) | Q(email=username)
password = kwargs.pop("password", None)
try:
user = User.objects.get(username_or_email, **kwargs)
except User.DoesNotExist:
pass
else:
if user.check_password(password):
return user
else:
if 'uidb36' not in kwargs:
return
kwargs["id"] = base36_to_int(kwargs.pop("uidb36"))
token = kwargs.pop("token")
try:
user = User.objects.get(**kwargs)
except User.DoesNotExist:
pass
else:
if default_token_generator.check_token(user, token):
return user
可能问题是没有get_user方法,所以我试试这个,如果不行就回来
EDIT2
添加的 get_user 方法没有任何变化...有什么想法吗?
【问题讨论】:
【参考方案1】:我认为您的问题来自这样一个事实,即您的新用户模型虽然注册到 settings.py 没有关联的身份验证后端。因此,他无法在您的应用中进行身份验证。
按照本教程:https://docs.djangoproject.com/en/dev/topics/auth/customizing/ 你应该有一个看起来像这样的文件:
from django.conf import settings
from django.contrib.auth.models import User, check_password
class SettingsBackend(object):
"""
Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.
Use the login name, and a hash of the password. For example:
ADMIN_LOGIN = 'admin'
ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'
"""
def authenticate(self, username=None, password=None):
login_valid = (settings.ADMIN_LOGIN == username)
pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
if login_valid and pwd_valid:
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
# Create a new user. Note that we can set password
# to anything, because it won't be checked; the password
# from settings.py will.
user = User(username=username, password='get from settings.py')
user.is_staff = True
user.is_superuser = True
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
在settings.py
这样注册:
AUTHENTICATION_BACKENDS ('mybackend',)
您可能还需要一个覆盖django.contrib.auth.admin.UserAdmin
的admin.py
文件
然后就可以注册了
admin.site.register(get_user_model(), YourUserAdmin)
为了能够在管理控制台中看到它。
PS is_staff 和 is_superuser 应该是可调用的,而不是布尔值
【讨论】:
【参考方案2】:好吧,是 django-grappelli 搞砸了我的管理员。我将其更改为 grappelli_safe,现在一切都很好:)
【讨论】:
以上是关于无法使用自定义用户和 Mezzanine/South 登录到 Django Admin的主要内容,如果未能解决你的问题,请参考以下文章
无法使用带有自定义 UserDetail 和 AuthenticationProvider 的 Spring Security 来阻止用户多次登录