password logoutview loginview loginrequired custom python django web authentication

python - logoutview - password django



check_password() de un usuario otra vez (3)

Gracias de nuevo a Yuji. Funciona cuando no tengo en mi primera def __init__ la variable usuario. También agregué en def clean_password las primeras 2 líneas del def clean_email

from django import forms from django.db.models.loading import cache from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User class EmailChangeForm(forms.Form): email = forms.EmailField(label=''New E-mail'', max_length=75) password = forms.CharField(widget=forms.PasswordInput) def __init__(self, *args, **kwargs): self.user = user super(EmailChangeForm, self).__init__(*args, **kwargs) def clean_password(self): User = cache.get_model(''auth'', ''User'') user = User.objects.get(username__exact=self.username) valid = user.check_password(self.cleaned_data[''password'']) if not valid: raise forms.ValidationError("Password Incorrect") return valid def __init__(self, username=None, *args, **kwargs): """Constructor. **Mandatory arguments** ``username`` The username of the user that requested the email change. """ self.username = username super(EmailChangeForm, self).__init__(*args, **kwargs) def clean_email(self): """Checks whether the new email address differs from the user''s current email address. """ email = self.cleaned_data.get(''email'') User = cache.get_model(''auth'', ''User'') user = User.objects.get(username__exact=self.username) # Check if the new email address differs from the current email address. if user.email == email: raise forms.ValidationError(''New email address cannot be the same / as your current email address'') return email

Tengo el siguiente formulario. ¿Cómo puedo verificar la contraseña del usuario nuevamente, antes de que el usuario pueda cambiar su emailadsress finalmente? Incluso él está conectado, solo quiero estar seguro de que realmente es el usuario. Sólo una cosa segura.

¿Cómo lo hago con .check_password() ?

''EmailChangeForm'' object has no attribute ''user'' /home/craphunter/workspace/project/trunk/project/auth/user/email_change/forms.py in clean_password, line 43 from django import forms from django.db.models.loading import cache from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User class EmailChangeForm(forms.Form): email = forms.EmailField(label=''New E-mail'', max_length=75) password = forms.CharField(widget=forms.PasswordInput) def __init__(self, user, *args, **kwargs): super(EmailChangeForm, self).__init__(*args, **kwargs) self.user = user def clean_password(self): valid = self.user.check_password(self.cleaned_data[''password'']) if not valid: raise forms.ValidationError("Password Incorrect") return valid def __init__(self, username=None, *args, **kwargs): """Constructor. **Mandatory arguments** ``username`` The username of the user that requested the email change. """ self.username = username super(EmailChangeForm, self).__init__(*args, **kwargs) def clean_email(self): """Checks whether the new email address differs from the user''s current email address. """ email = self.cleaned_data.get(''email'') User = cache.get_model(''auth'', ''User'') user = User.objects.get(username__exact=self.username) # Check if the new email address differs from the current email address. if user.email == email: raise forms.ValidationError(''New email address cannot be the same / as your current email address'') return email


Me gustaría refactorizar su código para ver algo como esto:

Ver:

@login_required def view(request, extra_context=None, ...): form = EmailChangeForm(user=request.user, data=request.POST or None) if request.POST and form.is_valid(): send_email_change_request(request.user, form.cleaned_data[''email''], https=request.is_secure()) return redirect(success_url) ...

La validación de la contraseña pasa a formar:

class EmailChangeForm(Form): email = ... old_password = CharField(..., widget=Password()) def __init__(self, user, data=None): self.user = user super(EmailChangeForm, self).__init__(data=data) def clean_old_password(self): password = self.cleaned_data.get(''password'', None) if not self.user.check_password(password): raise ValidationError(''Invalid password'')

Extraer la lógica de la vista:

def send_email_change_request(user, new_email, https=True): site = cache.get_model(''sites'', ''Site'') email = new_email verification_key = generate_key(user, email) current_site = Site.objects.get_current() site_name = current_site.name domain = current_site.domain protocol = ''https'' if https else ''http'' # First clean all email change requests made by this user qs = EmailChangeRequest.objects.filter(user=request.user) qs.delete() # Create an email change request change_request = EmailChangeRequest( user = request.user, verification_key = verification_key, email = email ) change_request.save() # Prepare context c = { ''email'': email, ''site_domain'': ''dev.tolisto.de'', ''site_name'': ''tolisto'', ''user'': self.user, ''verification_key'': verification_key, ''protocol'': protocol, } c.update(extra_context) context = Context(c) # Send success email subject = "Subject" # I don''t think that using template for # subject is good idea message = render_to_string(email_message_template_name, context_instance=context) send_mail(subject, message, None, [email])

No coloque cosas complicadas dentro de las vistas (como renderizar y enviar correos electrónicos).


Siento que respondiste tu propia pregunta:)

Los documentos sobre el método check_password están aquí: http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.models.User.check_password

success = user.check_password(request.POST[''submitted_password'']) if success: # do your email changing magic else: return http.HttpResponse("Your password is incorrect") # or more appropriately your template with errors

Ya que está pasando la solicitud. Usuario a su constructor de formularios (parece que ha __init__ por sus propias razones), podría poner toda su lógica en el formulario sin ningún problema.

class MyForm(forms.Form): # ... password = forms.CharField(widget=forms.PasswordInput) def __init__(self, user, *args, **kwargs): super(MyForm, self).__init__(*args, **kwargs) self.user = user def clean_password(self): valid = self.user.check_password(self.cleaned_data[''password'']) if not valid: raise forms.ValidationError("Password Incorrect") return valid

actualizar despues de ver tus formularios

DE ACUERDO. El problema principal es que __init__ se ha definido dos veces, haciendo inútil la primera declaración. El segundo problema que veo es que estaríamos haciendo múltiples consultas para el user cuando realmente no tenemos que hacerlo.

Nos hemos alejado bastante de tu pregunta original, pero espero que esta sea una experiencia de aprendizaje.

He cambiado sólo algunas cosas:

  • Se eliminó la definición extra de __init__
  • Se cambió __init__ para aceptar una instancia de User lugar de un username texto
  • Se eliminó la consulta de User.objects.get(username=username) ya que estamos pasando un objeto de usuario.

Solo recuerde pasar el constructor de formulario user=request.user lugar de username=request.user.username

class EmailChangeForm(forms.Form): email = forms.EmailField(label=''New E-mail'', max_length=75) password = forms.CharField(widget=forms.PasswordInput) def __init__(self, user=None, *args, **kwargs): self.user = user super(EmailChangeForm, self).__init__(*args, **kwargs) def clean_password(self): valid = self.user.check_password(self.cleaned_data[''password'']) if not valid: raise forms.ValidationError("Password Incorrect") def clean_email(self): email = self.cleaned_data.get(''email'') # no need to query a user object if we''re passing it in anyways. user = self.user # Check if the new email address differs from the current email address. if user.email == email: raise forms.ValidationError(''New email address cannot be the same / as your current email address'') return email

Finalmente, ya que estamos hablando de buenas prácticas aquí, recomiendo seguir con las sugerencias de Skirmantas sobre cómo mover su código de vista actual a un método de formulario para que pueda llamar a myform.send_confirmation_email .

¡Suena como un buen ejercicio!