2012-02-03 19 views
6

Para cambiar la contraseña, estoy usando auth_views.password_change y para restablecer la contraseña auth_views.password_reset.¿Cómo recibir una notificación cuando un usuario cambia la contraseña o solicita un restablecimiento de contraseña?

¿Cómo puedo recibir una notificación cuando un usuario cambia correctamente su contraseña? No necesito saber la contraseña anterior ni la nueva. Solo que el evento tuvo lugar y para qué usuario.

De manera similar, me gustaría recibir una notificación cuando alguien solicite un restablecimiento de contraseña y también cuando completen con éxito el procedimiento de restablecimiento.

¿Puedo hacer lo anterior con señales o algunos parches simples? ¿O necesito escribir mis propios puntos de vista para hacer esto?

Respuesta

7

Crear un decorador:

def notify_admins(func): 
    def wrapper(request, *args, **kwargs): 
     # send email to admins 
     return func(request, *args, **kwargs) 
    return wrapper 

Entonces, justo add se envuelve alrededor de los puntos de vista apropiados en su urls.py:

urlpatterns = patterns('', 
    ... 
    (r'^password_change/done/$', notify_admins(auth_views.password_change_done)), 
    (r'^password_reset/done/$', notify_admins(auth_views.password_reset_done)), 
    (r'^reset/done/$', notify_admins(auth_views.password_reset_complete)), 
    ... 
) 

Tenga en cuenta que el envío de correo electrónico directamente desde un punto de vista, o en este caso un decorador, se unirá a la solicitud. En lugar de enviar el correo electrónico allí directamente, sería mejor crear una señal personalizada y un controlador que activará un hilo para enviar el correo electrónico. Luego, en el decorador, simplemente envía la señal.

+0

¿Sin embargo, las señales de Arent son sincrónicas? A menos que el correo ocurra en un proceso de asincronización, ¿no sería lo mismo? – jdi

+1

De ahí el bit "disparar un hilo". Si crea un hilo para enviar el correo electrónico en la señal, se convierte en asíncrono. La señal devuelve el procesamiento y el nuevo hilo se adapta a su proceso de envío de correo electrónico. –

+0

Ah se perdió ese poquito. Solo se centró en las señales – jdi

2

Si ya está utilizando el auth_views.password_change construyeron a la vista, entonces sería fácil para notificar a sí mismo una vez que se redirigen después de un cambio exitoso:

https://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.views.password_change

password_change(request[, template_name, post_change_redirect, password_change_form])

Si se establece el post_change_redirect url para redirigir a una de sus propias vistas, luego simplemente tome cualquier acción que desee en esa vista para enviar una notificación (correo electrónico, actualizaciones de base de datos, etc.).

Usted podría incluso, en su opinión redirección, simplemente hacer su notificación y luego regresar password_change_done(request[, template_name])

+1

esto funcionaría. Sin embargo, una actualización en esa URL también desencadenaría la acción. Incluso cargar esa URL a mano lo desencadenaría. Preferiría evitar estas formas raras, pero potenciales, de notificarme erróneamente sobre un cambio de contraseña. –

+0

Estoy de acuerdo en que se desencadenaría. Mi respuesta fue principalmente la parte de su pregunta sobre no tener que escribir realmente su propia visión completa. Esto solo se aprovecha de los existentes. Como se sugiere en la otra respuesta, debe hacerlo a través del manejador de envío de formulario real. – jdi

4

Se puede escribir una costumbre password_change_form que se pasa a password_change. Este formulario extendería el PasswordChangeForm de django anulando su método de guardado para primero notificarle el cambio y luego llamar al método de guardado PasswordChangeForm de su padre.

Docs en vista password_change: https://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.views.password_change

Docs en ChangeForm: https://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.forms.PasswordChangeForm

código para PasswordChangeForm: https://code.djangoproject.com/browser/django/trunk/django/contrib/auth/forms.py

1

También podría capturar la señal y verificar si la contraseña ha cambiado. Solo tenga en cuenta que este código se ejecutará cada vez que un usuario cambie.

@receiver(pre_save, sender=User) 
def record_password_change(sender, **kwargs): 
    user = kwargs.get('instance', None) 
    if user: 
     new_password = user.password 
     try: 
      old_password = User.objects.get(pk=user.pk).password 
     except User.DoesNotExist: 
      old_password = None 

     if new_password != old_password: 
      # do what you need here 
+0

También tenga en cuenta que si su administrador cambia los parámetros de la contraseña, se llamará a este manejador de señales para cada usuario la próxima vez que inicie sesión. Esto es importante si pretende aplicar políticas de caducidad de contraseñas utilizando este manejador de señal . – mkoistinen

2

A partir de Django 1.9, puede definir sus propios validadores de contraseñas. Incluso podría simplemente redefinir uno existente, si lo desea.Cuando lo haces, agrega un método:

from django.contrib.auth.password_validation import MinimumLengthValidator 
class MyPasswordValidator(MinimumLengthValidator): 

    def password_changed(self, password, user): 
     # put your password changed logic here 

Asegúrese de incluir la nueva clase en la configuración de la siguiente manera:

AUTH_PASSWORD_VALIDATORS = [ 
    { 
     'NAME': 'my_package.password_validators.MyPasswordValidator', 
     'OPTIONS': { 
      'min_length': 8, 
     } 
    }, 
    ... 
] 

Ahora, cada vez que se cambia una contraseña por el usuario, su MyPasswordValidator clase será notificado. En mi experiencia, esta es la mejor manera de hacer esto porque:

  1. Al utilizar señales para capturar estos eventos, también puede capturar eventos en los que el sistema de re-codificado una contraseña existente debido a un cambio en el hashing parámetros, en la mayoría de los casos, no le gustaría capturar estos eventos y no hay una forma obvia de evitarlo con señales.
  2. Puede simplemente agregar una llamada de función en el método save() de todos sus formularios de manejo de contraseñas, pero esto se vuelve difícil cuando quiere hacer lo mismo con el formulario incorporado de contraseña de administrador y no lo ayudará si los cambios de contraseña se realizan mediante programación fuera de un formulario.

Le advierto que tenga en cuenta que el parámetro de contraseña en password_changed() es, de hecho, la contraseña sin formato del usuario. Tenga cuidado al manejar esto y nunca lo guarde en ningún lugar desencriptado/sin grabar.

Cuestiones relacionadas