Existe uma boa maneira de fazer isso no Django sem lançar meu próprio sistema de autenticação? Quero que o nome de usuário seja o endereço de e-mail do usuário em vez de criar um nome de usuário.
Por favor, avise, obrigado.
python
django
authentication
Damon
fonte
fonte
Respostas:
Para qualquer pessoa que queira fazer isso, eu recomendo dar uma olhada em django-email-as-username que é uma solução bastante abrangente, que inclui remendar o administrador e os
createsuperuser
comandos de gerenciamento, entre outras partes.Edit : A partir do Django 1.5 em diante, você deve considerar o uso de um modelo de usuário personalizado ao invés de django-email-as-username .
fonte
Aqui está o que fazemos. Não é uma solução "completa", mas faz muito do que você está procurando.
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)
fonte
Esta é uma maneira de fazer isso para que o nome de usuário e o e-mail sejam aceitos:
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
Não sei se há alguma configuração para definir o formulário de autenticação padrão, mas você também pode substituir o url em urls.py
url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'),
Aumentar o ValidationError evitará 500 erros quando um e-mail inválido for enviado. Usar a definição do super para "invalid_login" mantém a mensagem de erro ambígua (em vez de um específico "nenhum usuário por esse e-mail encontrado"), que seria necessário para evitar vazar se um endereço de e-mail está inscrito em uma conta em seu serviço. Se essas informações não estiverem seguras em sua arquitetura, pode ser mais fácil ter uma mensagem de erro mais informativa.
fonte
Django agora fornece um exemplo completo de um sistema de autenticação estendido com admin e formulário: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example
Você pode basicamente copiar / colar e adaptar (eu não precisava do
date_of_birth
no meu caso).Na verdade, ele está disponível desde o Django 1.5 e ainda está disponível a partir de agora (django 1.7).
fonte
Se você for estender o modelo de usuário, terá que implementar o modelo de usuário personalizado de qualquer maneira.
Aqui está um exemplo para Django 1.8. Django 1.7 exigiria um pouco mais de trabalho, principalmente mudando as formas padrão (apenas dê uma olhada em
UserChangeForm
&UserCreationForm
indjango.contrib.auth.forms
- é isso que você precisa no 1.7).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'
fonte
username
campo paraSiteUser
modelar, porque, quando executo opython manage.py makemigrations ...
comando, recebo esta saída:ERRORS: <class 'accounts.admin.UserAdmin'>: (admin.E033) The value of 'ordering[0]' refers to 'username', which is not an attribute of 'accounts.User'.
username
campo ao meuUser
modelo com seunull=True
atributo. Nesta entrada de pasta de colar eu queria mostrar a implementação. pastebin.com/W1PgLrD9Outras alternativas parecem muito complexas para mim, então escrevi um snippet que permite autenticar usando nome de usuário, e-mail ou ambos, e também habilitar ou desabilitar a distinção entre maiúsculas e minúsculas. Eu enviei para o pip como django-dual-authentication .
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
fonte
A última versão do django-registration permite uma boa personalização e pode fazer o trabalho - docs aqui https://bitbucket.org/ubernostrum/django-registration/src/fad7080fe769/docs/backend-api.rst
fonte
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()
funcionando perfeitamente ... para django 1.11.4
fonte
você também pode encontrar uma discussão interessante sobre este tópico no link abaixo:
http://groups.google.com/group/django-users/browse_thread/thread/c943ede66e6807c/2fbf2afeade397eb#2fbf2afeade397eb
fonte
A maneira mais fácil é consultar o nome de usuário com base no e-mail na visualização de login. Dessa forma, você pode deixar todo o resto sozinho:
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))
Em seu modelo, defina a próxima variável de acordo, ou seja,
<form method="post" class="form-login" action="{% url 'login' %}?next={{ request.GET.next }}" accept-charset="UTF-8">
E forneça às entradas de nome de usuário / senha os nomes corretos, ou seja, nome de usuário e senha.
ATUALIZAÇÃO :
Alternativamente, o if _is_valid_email (email): call pode ser substituído por if '@' no nome de usuário. Dessa forma, você pode descartar a função _is_valid_email. Isso realmente depende de como você define seu nome de usuário. Não funcionará se você permitir o caractere '@' em seus nomes de usuário.
fonte
Acho que a maneira mais rápida é criar um formulário herdar de
UserCreateForm
e, em seguida, substituir ousername
campo porforms.EmailField
. Então, para cada novo usuário de registro, eles precisam se conectar com seu endereço de e-mail.Por exemplo:
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> ...
fonte
UserCreationForm
classe? E, por favor, não recomendo escrever<input …
quando, com certeza,{{form.username}}
é melhor.Não tenho certeza se as pessoas estão tentando fazer isso, mas descobri uma maneira legal (e limpa) de apenas pedir o e-mail e definir o nome de usuário como o e-mail na visualização antes de salvar.
Meu UserForm requer apenas o e-mail e a senha:
class UserForm(forms.ModelForm): password = forms.CharField(widget=forms.PasswordInput()) class Meta: model = User fields = ('email', 'password')
Então, na minha opinião, adiciono a seguinte lógica:
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()
fonte