vincent register page loginview example custom and python django authentication

python - page - register and login django



Aceptar dirección de correo electrónico como nombre de usuario en Django (12)

¿Hay una buena manera de hacer esto en django sin rodar mi propio sistema de autenticación? Quiero que el nombre de usuario sea la dirección de correo electrónico del usuario en lugar de que creen un nombre de usuario.

Por favor asesorar, gracias.


Creo que la forma más rápida es crear un formulario heredado de UserCreateForm y luego anular el campo de username con forms.EmailField . Luego, para cada nuevo usuario de registro, debe iniciar sesión con su dirección de correo electrónico.

Por ejemplo:

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> ...


Django ahora proporciona un ejemplo completo de un sistema de autenticación extendido con administrador y formulario: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example

Básicamente puedes copiarlo y pegarlo y adaptarlo (no necesité la date_of_birth en mi caso).

En realidad está disponible desde Django 1.5 y todavía está disponible a partir de ahora (django 1.7).


Esta es una forma de hacerlo para que se acepten tanto el nombre de usuario como el correo electrónico:

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

No sé si hay alguna configuración para establecer el formulario de autenticación predeterminado, pero también puede anular la url en urls.py

url(r''^accounts/login/$'', ''django.contrib.auth.views.login'', { ''authentication_form'': EmailAuthenticationForm }, name=''login''),

Elevar ValidationError evitará 500 errores cuando se envíe un correo electrónico no válido. Usar la definición del super para "invalid_login" mantiene el mensaje de error ambiguo (frente a un "no usuario encontrado por ese correo electrónico" específico) que se requeriría para evitar filtraciones de si una dirección de correo electrónico está registrada para una cuenta en su servicio. Si esa información no es segura en su arquitectura, podría ser más amigable tener un mensaje de error más informativo.


Esto es lo que hacemos. No es una solución "completa", pero hace mucho de lo que estás buscando.

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)



La forma más fácil es buscar el nombre de usuario basado en el correo electrónico en la vista de inicio de sesión. De esa forma puedes dejar todo lo demás solo:

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))

En su plantilla configure la siguiente variable en consecuencia, es decir,

<form method="post" class="form-login" action="{% url ''login'' %}?next={{ request.GET.next }}" accept-charset="UTF-8">

Y proporcione a sus entradas de nombre de usuario / contraseña los nombres correctos, es decir, nombre de usuario, contraseña.

ACTUALIZAR :

Alternativamente, la llamada if _is_valid_email (email): puede reemplazarse con ''@'' en username. De esta forma, puede descartar la función _is_valid_email. Esto realmente depende de cómo defines tu nombre de usuario. No funcionará si permite el carácter ''@'' en sus nombres de usuario.


No estoy seguro de si la gente está tratando de lograr esto, pero encontré una buena (y limpia) forma de solo solicitar el correo electrónico y luego establecer el nombre de usuario como el correo electrónico en la vista antes de guardar.

Mi UserForm solo requiere el correo electrónico y la contraseña:

class UserForm(forms.ModelForm): password = forms.CharField(widget=forms.PasswordInput()) class Meta: model = User fields = (''email'', ''password'')

Entonces, en mi opinión, agrego la siguiente 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()


Otras alternativas parecen demasiado complejas para mí, así que escribí un fragmento que permite autenticar usando nombre de usuario, correo electrónico o ambos, y también habilita o deshabilita las mayúsculas y minúsculas. Lo cargué a 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


Si va a extender el modelo de usuario, tendrá que implementar un modelo de usuario personalizado de todos modos.

Aquí hay un ejemplo para Django 1.8. Django 1.7 requeriría un poco más de trabajo, en su mayoría cambiando los formularios por defecto (solo echa un vistazo a UserChangeForm y UserCreationForm en django.contrib.auth.forms , eso es lo que necesitas en 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''




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()

trabajando perfectamente ... para django 1.11.4