Bunu django'da kendi kimlik doğrulama sistemimi yuvarlamadan yapmanın iyi bir yolu var mı? Kullanıcı adının, bir kullanıcı adı oluşturmak yerine kullanıcının e-posta adresi olmasını istiyorum.
Lütfen tavsiye verin, teşekkür ederim.
Bunu django'da kendi kimlik doğrulama sistemimi yuvarlamadan yapmanın iyi bir yolu var mı? Kullanıcı adının, bir kullanıcı adı oluşturmak yerine kullanıcının e-posta adresi olmasını istiyorum.
Lütfen tavsiye verin, teşekkür ederim.
Yanıtlar:
Bunu yapmak isteyenler için, oldukça kapsamlı bir çözüm olan django-email-as-username'e bir göz atmanızı tavsiye ederim createsuperuser
.
Düzenleme : Django 1.5'ten itibaren , django-e-posta-kullanıcı adı yerine özel bir kullanıcı modeli kullanmayı düşünmelisiniz .
İşte yaptığımız şey. Bu "eksiksiz" bir çözüm değil, ancak aradığınız şeyin çoğunu yapıyor.
from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
class Meta:
model = User
exclude = ('email',)
username = forms.EmailField(max_length=64,
help_text="The person's email address.")
def clean_email(self):
email = self.cleaned_data['username']
return email
class UserAdmin(UserAdmin):
form = UserForm
list_display = ('email', 'first_name', 'last_name', 'is_staff')
list_filter = ('is_staff',)
search_fields = ('email',)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Hem kullanıcı adının hem de e-postanın kabul edilmesi için bunu yapmanın bir yolu:
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.forms import ValidationError
class EmailAuthenticationForm(AuthenticationForm):
def clean_username(self):
username = self.data['username']
if '@' in username:
try:
username = User.objects.get(email=username).username
except ObjectDoesNotExist:
raise ValidationError(
self.error_messages['invalid_login'],
code='invalid_login',
params={'username':self.username_field.verbose_name},
)
return username
Varsayılan Kimlik Doğrulama formunu ayarlamak için bir ayar olup olmadığını bilmiyorum, ancak urls.py'deki url'yi de geçersiz kılabilirsiniz.
url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'),
ValidationError'ı yükseltmek, geçersiz bir e-posta gönderildiğinde 500 hatayı önleyecektir. Üstün "valid_login "için tanımını kullanmak, hizmetinizdeki bir hesap için bir e-posta adresine kaydolup kaydolmadığında sızıntıyı önlemek için gerekli olan hata mesajını belirsiz tutar (belirli bir" bu e-postayla hiçbir kullanıcı bulunamadı "karşısında). Bu bilgiler mimarinizde güvenli değilse, daha bilgilendirici bir hata mesajı almak daha kolay olabilir.
Django şimdi, yönetici ve form ile genişletilmiş bir kimlik doğrulama sisteminin tam bir örneğini sunuyor: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example
Temelde kopyalayabilir / yapıştırabilir ve uyarlayabilirsiniz ( date_of_birth
benim durumumda buna ihtiyacım yoktu ).
Aslında Django 1.5'ten beri mevcuttur ve şu an itibariyle hala mevcuttur (django 1.7).
Kullanıcı modelini genişletecekseniz, yine de özel kullanıcı modelini uygulamanız gerekecektir.
İşte Django 1.8 için bir örnek. Bir az şey gerektirecektir Django 1.7 çoğunlukla varsayılan formları (sadece bakmak değişen, daha fazla iş bit UserChangeForm
& UserCreationForm
içinde django.contrib.auth.forms
- Eğer 1.7 in gerekenler olduğunu).
user_manager.py:
from django.contrib.auth.models import BaseUserManager
from django.utils import timezone
class SiteUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
today = timezone.now()
if not email:
raise ValueError('The given email address must be set')
email = SiteUserManager.normalize_email(email)
user = self.model(email=email,
is_staff=False, is_active=True, **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, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u
models.py:
from mainsite.user_manager import SiteUserManager
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
class SiteUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, blank=False)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
objects = SiteUserManager()
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
forms.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from mainsite.models import SiteUser
class MyUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = SiteUser
fields = ("email",)
class MyUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = SiteUser
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
add_form = MyUserCreationForm
fieldsets = (
(None, {'fields': ('email', 'password',)}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser',)}),
('Groups', {'fields': ('groups', 'user_permissions',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
list_display = ('email', )
list_filter = ('is_active', )
search_fields = ('email',)
ordering = ('email',)
admin.site.register(SiteUser, MyUserAdmin)
settings.py:
AUTH_USER_MODEL = 'mainsite.SiteUser'
username
alanı SiteUser
modele python manage.py makemigrations ...
ERRORS: <class 'accounts.admin.UserAdmin'>: (admin.E033) The value of 'ordering[0]' refers to 'username', which is not an attribute of 'accounts.User'.
username
benim için alanını User
kendi barındıran model null=True
özelliğinde. Bu yapıştırma kutusu girişinde uygulamayı göstermek istedim. pastebin.com/W1PgLrD9
Diğer alternatifler benim için çok karmaşık görünüyor, bu yüzden kullanıcı adı, e-posta veya her ikisini kullanarak kimlik doğrulamaya izin veren ve ayrıca büyük / küçük harfe duyarlı olanı etkinleştiren veya devre dışı bırakan bir pasaj yazdım. Bunu pip'e django-dual-authentication olarak yükledim .
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.conf import settings
###################################
""" DEFAULT SETTINGS + ALIAS """
###################################
try:
am = settings.AUTHENTICATION_METHOD
except:
am = 'both'
try:
cs = settings.AUTHENTICATION_CASE_SENSITIVE
except:
cs = 'both'
#####################
""" EXCEPTIONS """
#####################
VALID_AM = ['username', 'email', 'both']
VALID_CS = ['username', 'email', 'both', 'none']
if (am not in VALID_AM):
raise Exception("Invalid value for AUTHENTICATION_METHOD in project "
"settings. Use 'username','email', or 'both'.")
if (cs not in VALID_CS):
raise Exception("Invalid value for AUTHENTICATION_CASE_SENSITIVE in project "
"settings. Use 'username','email', 'both' or 'none'.")
############################
""" OVERRIDDEN METHODS """
############################
class DualAuthentication(ModelBackend):
"""
This is a ModelBacked that allows authentication
with either a username or an email address.
"""
def authenticate(self, username=None, password=None):
UserModel = get_user_model()
try:
if ((am == 'email') or (am == 'both')):
if ((cs == 'email') or cs == 'both'):
kwargs = {'email': username}
else:
kwargs = {'email__iexact': username}
user = UserModel.objects.get(**kwargs)
else:
raise
except:
if ((am == 'username') or (am == 'both')):
if ((cs == 'username') or cs == 'both'):
kwargs = {'username': username}
else:
kwargs = {'username__iexact': username}
user = UserModel.objects.get(**kwargs)
finally:
try:
if user.check_password(password):
return user
except:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user.
UserModel().set_password(password)
return None
def get_user(self, username):
UserModel = get_user_model()
try:
return UserModel.objects.get(pk=username)
except UserModel.DoesNotExist:
return None
Django kaydının en son sürümü güzel bir özelleştirme sağlar ve işi yapabilir - buradaki dokümanlar https://bitbucket.org/ubernostrum/django-registration/src/fad7080fe769/docs/backend-api.rst
aşağıdaki bağlantıda bu konuyla ilgili ilginç bir tartışma da bulabilirsiniz:
En kolay yol, giriş görünümündeki e-postaya göre kullanıcı adını aramaktır. Bu şekilde diğer her şeyi rahat bırakabilirsiniz:
from django.contrib.auth import authenticate, login as auth_login
def _is_valid_email(email):
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
try:
validate_email(email)
return True
except ValidationError:
return False
def login(request):
next = request.GET.get('next', '/')
if request.method == 'POST':
username = request.POST['username'].lower() # case insensitivity
password = request.POST['password']
if _is_valid_email(username):
try:
username = User.objects.filter(email=username).values_list('username', flat=True)
except User.DoesNotExist:
username = None
kwargs = {'username': username, 'password': password}
user = authenticate(**kwargs)
if user is not None:
if user.is_active:
auth_login(request, user)
return redirect(next or '/')
else:
messages.info(request, "<stvrong>Error</strong> User account has not been activated..")
else:
messages.info(request, "<strong>Error</strong> Username or password was incorrect.")
return render_to_response('accounts/login.html', {}, context_instance=RequestContext(request))
Şablonunuzda sonraki değişkeni buna göre ayarlayın, yani
<form method="post" class="form-login" action="{% url 'login' %}?next={{ request.GET.next }}" accept-charset="UTF-8">
Ve kullanıcı adı / şifre girişlerinize doğru isimleri, yani kullanıcı adı, şifreyi verin.
GÜNCELLEME :
Alternatif olarak, if _is_valid_email (e-posta): çağrısı, kullanıcı adındaki if '@' ile değiştirilebilir. Bu şekilde _is_valid_email işlevini bırakabilirsiniz. Bu gerçekten kullanıcı adınızı nasıl tanımladığınıza bağlıdır. Kullanıcı adlarınızda '@' karakterine izin verirseniz çalışmayacaktır.
Bence en hızlı yol, formdan devralacak bir form oluşturmak UserCreateForm
ve ardından username
alanı ile geçersiz kılmaktır forms.EmailField
. Daha sonra her yeni kayıt kullanıcısı için e-posta adresleriyle oturum açmaları gerekir.
Örneğin:
urls.py
...
urlpatterns += url(r'^signon/$', SignonView.as_view(), name="signon")
views.py
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
class UserSignonForm(UserCreationForm):
username = forms.EmailField()
class SignonView(CreateView):
template_name = "registration/signon.html"
model = User
form_class = UserSignonForm
signon.html
...
<form action="#" method="post">
...
<input type="email" name="username" />
...
</form>
...
UserCreationForm
sınıfta hangi parçacığın kullanılacağını yalnızca tanımlayabiliyorsanız neden alt sınıf? Ve lütfen daha iyi <input …
olduğunda yazmayı önermeyin {{form.username}}
.
İnsanların bunu başarmaya çalıştığından emin değilim, ancak yalnızca e-postayı istemenin güzel (ve temiz) bir yolunu buldum ve ardından kaydetmeden önce görünümde kullanıcı adını e-posta olarak ayarladım.
UserForm'um yalnızca e-posta ve şifre gerektirir:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('email', 'password')
Sonra benim görüşüme göre aşağıdaki mantığı ekliyorum:
if user_form.is_valid():
# Save the user's form data to a user object without committing.
user = user_form.save(commit=False)
user.set_password(user.password)
#Set username of user as the email
user.username = user.email
#commit
user.save()