2009-05-04 8 views
21

Desidero consentire solo una sessione autenticata alla volta per un accesso individuale nella mia applicazione Django. Quindi, se un utente è connesso alla pagina web su un dato indirizzo IP e quelle stesse credenziali utente sono utilizzate per accedere da un indirizzo IP diverso, voglio fare qualcosa (o disconnettersi dal primo utente o negare l'accesso al secondo utente).Come posso rilevare più accessi in un'applicazione web Django da posizioni diverse?

risposta

18

Non sono sicuro se questo è ancora necessario, ma pensato vorrei condividere la mia soluzione:

1) Installare django-tracking (grazie per quella punta Van Gale Google Maps + GeoIP è incredibile!)

2) Aggiungi il middleware:

from django.contrib.sessions.models import Session 
from tracking.models import Visitor 
from datetime import datetime 

class UserRestrictMiddleware(object): 
    """ 
    Prevents more than one user logging in at once from two different IPs 
    """ 
    def process_request(self, request): 
     ip_address = request.META.get('REMOTE_ADDR','') 
     try: 
      last_login = request.user.last_login 
     except: 
      last_login = 0 
     if unicode(last_login)==unicode(datetime.now())[:19]: 
      previous_visitors = Visitor.objects.filter(user=request.user).exclude(ip_address=ip_address) 
      for visitor in previous_visitors: 
       Session.objects.filter(session_key=visitor.session_key).delete() 
       visitor.user = None 
       visitor.save() 

3) Assicurarsi che va dopo il VisitorTrackingMiddleware e si dovrebbe trovare gli account di accesso precedenti vengono spostate automaticamente quando qualcuno di nuovo log in :)

+0

Possiamo fidarci di django-tracking dopo tutti questi anni di inattività? – NikosKeyz

6

Avrete bisogno di farlo con middleware personalizzato.

nel metodo middleware process_request() si avrà accesso all'oggetto richiesta in modo che si può fare qualcosa di simile al seguente:

session_key = request.session.session_key 
ip_address = request.META.get('REMOTE_ADDR', '') 

Ora si conosce l'indirizzo IP, in modo da controllare un modello a fare una (più o meno) sarebbe simile a questa:

class SessionIPS(models.Model): 
    session = models.ForeignKey(Session) 
    IP = models.CharField(max_length=20) 

Così, quando una sessione viene creato o eliminato si modifiy tavolo la sessione di ip di conseguenza, e quando arriva una richiesta assicurarsi che l'indirizzo IP non viene utilizzato per un'altra sessione. Se if è, quindi restituire un Http404 (o qualcosa di simile) dal middleware.

Un'app collegabile che può mostrare molti più dettagli (e include persino l'indirizzo IP nel proprio modello) è django-tracking.

6

Django middleware probabilmente ti aiuterà a raggiungere questo obiettivo. Il problema è che probabilmente vorrai consentire più sessioni anonime dallo stesso indirizzo IP, anche sessioni autenticate per utenti diversi, ma non sessioni autenticate per lo stesso utente.

si vorrà:

  1. creare un modello di profilo utente per memorizzare l'indirizzo IP di login di un utente. Vedi la documentazione di Django Storing additional information about users.

  2. Implementare uno custom authentication backend. Questo back-end, una volta attivato e autenticato con successo un utente (basta chiamare super) cancellerebbe l'ultimo IP di accesso dell'utente nel modello del profilo.

  3. Implementare una sottoclasse della classe django.contrib.sessions.SessionMiddleware di Django. Implementare process_request. Se il modello del profilo dell'oggetto request.user non ha un indirizzo IP, impostarlo e consentire la richiesta. Se ha un IP e l'IP è diverso dall'IP della richiesta corrente (request.META.REMOTE_ADDR), fare ciò che si desidera disconnettere l'altro utente o restituire un errore al richiedente.

  4. Aggiornare il file settings.py in modo che il back-end di autenticazione personalizzato venga elaborato per primo e in modo che anche il middleware di sessione personalizzato venga elaborato per primo. Ciò comporta l'aggiornamento di settings.AUTHENTICATION_BACKENDS e settings.MIDDLEWARE_CLASSES.

9

Se si' re già usando django-tracking come suggerito qui, c'è un modo molto più facile da implementare questa:

Definire un gestore di segnale:

# myapp/signals.py 
def kick_my_other_sessions(sender, request=None, user=None, **kwargs): 
    from tracking.models import Visitor 
    from django.contrib.sessions.models import Session 
    keys = [v.session_key for v in Visitor.objects.filter(user=request.user).exclude(session_key=request.session.session_key)] 
    Session.objects.filter(session_key__in=keys).delete() 

creare un listener per il segnale user_logged_in:

# myapp/__init__.py 
from myapp.signals import kick_my_other_sessions 
from django.contrib.auth.signals import user_logged_in 
user_logged_in.connect(kick_my_other_sessions, sender=User) 

Ciò istituire una sorta di "ultima all'utente di accedere vittorie" del sistema. Se si desidera consentire più accessi dello stesso utente dallo stesso ip, è possibile aggiungere uno .exclude() alla ricerca Visitors.

+0

È utile anche impostare 'visitor.user = None' per ciascuno dei visitatori corrispondenti, altrimenti questo codice troverà ancora visitatori per sessioni già cancellate su ogni accesso. (Questo è importante se si decide di aggiungere un messaggio per comunicare all'utente appena connesso "è stato appena disconnesso da un'altra sessione"). – Duncan

Problemi correlati