2012-02-03 19 views
6

Per una modifica della password sto usando auth_views.password_change e per la reimpostazione della password auth_views.password_reset.Come ricevere una notifica quando un utente cambia password o richiede una reimpostazione della password?

Come posso ricevere una notifica quando un utente modifica la propria password con successo? Non ho bisogno di conoscere la password vecchia o nuova. Solo che l'evento ha avuto luogo e per quale utente.

Analogamente, vorrei ricevere una notifica quando qualcuno ha richiesto una reimpostazione della password e anche quando ha completato correttamente la procedura di ripristino.

Posso fare quanto sopra con segnali o qualche semplice patch? O devo scrivere le mie opinioni per farlo?

risposta

7

Creare un decoratore:

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

Poi, basta aggiunge avvolgerla intorno le viste appropriate nel tuo 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)), 
    ... 
) 

Tenete a mente che l'invio di e-mail direttamente da una vista, o in questo caso un decoratore, legherà la richiesta. Invece di inviare direttamente l'e-mail, sarebbe meglio creare un segnale personalizzato e un gestore che sparasse da una discussione per inviare effettivamente l'e-mail. Quindi, nel decoratore, si invia semplicemente il segnale.

+0

Segnali d'allarme sincrono però? A meno che la posta non avvenga in un processo asincrono, non sarebbe la stessa cosa? – jdi

+1

Quindi il bit "fire off a thread". Se si crea una discussione per inviare l'e-mail nel segnale, essa diventa effettivamente asincrona. Il segnale restituisce elaborazione e la nuova discussione passa felicemente al suo processo di invio della posta elettronica. –

+0

Ah, mi sono perso un po '. Concentrati solo sui segnali – jdi

2

Se si sta già utilizzando il auth_views.password_change costruito in vista, allora sarebbe facile comunicare se stessi una volta che essi vengono reindirizzati dopo un cambiamento di successo:

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

Se si imposta la post_change_redirect url per reindirizzare a una delle tue visualizzazioni, quindi puoi semplicemente prendere qualsiasi azione tu desideri in quella vista per inviare una notifica (email, aggiornamenti del database, ecc.).

si potrebbe anche, a suo avviso di reindirizzamento, basta fare la tua notifica e poi tornare password_change_done(request[, template_name])

+1

questo funzionerebbe. Tuttavia, un aggiornamento su tale URL attiverà anche l'azione. Anche caricando manualmente quell'URL lo farebbe scattare. Preferirei evitare questi rari, ma potenziali modi di comunicarmi erroneamente una modifica della password. –

+0

Sono d'accordo che si innescherebbe. La mia risposta è stata principalmente la parte della tua domanda sul non dover scrivere davvero la tua visione completa. Questo funziona semplicemente su quelli esistenti. Come suggerito nell'altra risposta, dovresti farlo attraverso l'attuale gestore di invio del modulo. – jdi

4

si potrebbe scrivere un personalizzato password_change_form che si passa a password_change. Questo modulo estenderebbe il django PasswordChangeForm sovrascrivendo il suo metodo di salvataggio per notificare prima la modifica e quindi chiamare il metodo di salvataggio principale PasswordChangeForm s genitore.

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

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

Codice per PasswordChangeForm: https://code.djangoproject.com/browser/django/trunk/django/contrib/auth/forms.py

1

È anche possibile acquisire il segnale e verificare se la password è stata modificata. Tieni presente che questo codice verrà eseguito ogni volta che un utente cambia.

@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

Ricorda inoltre che se l'amministratore modifica i parametri hasher della password, questo gestore di segnale verrà richiamato per ogni utente al successivo accesso. Questo è importante se si intende applicare le politiche di scadenza della password utilizzando questo gestore di segnale . – mkoistinen

2

A partire da Django 1.9, è possibile definire i propri validatori di password personali. Potresti anche semplicemente ridefinire uno esistente, se vuoi.Quando lo fai, aggiungi un metodo:

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

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

Assicurati di includere la nuova classe nelle impostazioni come segue:

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

Ora, ogni volta che una password viene modificata dall'utente, la classe MyPasswordValidator sarà notificato Nella mia esperienza, questo è il modo migliore per farlo, perché:

  1. Quando si utilizza segnali per catturare questi eventi, vi sarà anche catturare gli eventi in cui il sistema ricodificato una password esistente a causa di un cambiamento di hashing parametri, nella maggior parte dei casi, non vorrai catturare questi eventi e non c'è un modo ovvio per prevenirli con i segnali.
  2. È possibile aggiungere semplicemente una chiamata di funzione nel metodo save() di tutti i moduli di gestione delle password, ma diventa difficile quando si desidera fare lo stesso con il modulo di modifica della password di amministrazione incorporato e non sarà di aiuto se le modifiche alle password vengono eseguite a livello di programmazione all'esterno di un modulo.

Ti informerò che il parametro password in password_changed() è in effetti la password non valida dell'utente. Fare attenzione quando si maneggia questo e assolutamente non memorizzarlo ovunque non criptato/non alterato.

Problemi correlati