Pergunta

Gostaria de auditoria quando um usuário tem experimentado um tempo ocioso na minha aplicação Django. Em outras palavras, se a data de validade do cookie de sessão do usuário excede o SESSION_COOKIE_AGE encontrado em settings.py, o usuário é redirecionado para a página de login. Quando isso ocorre, uma auditoria também deve ocorrer. Por "auditoria", quero dizer um registro deve ser escrito para minha mesa person.audit.

Atualmente, eu tenha configurado algum middleware para capturar esses eventos. Infelizmente, Django gera um novo cookie quando o usuário é redirecionado para a página de login, então eu não posso determinar se o usuário foi levado para a página de login via um tempo ocioso ou algum outro evento.

Do que eu posso dizer, eu precisaria de trabalho com o quadro de "django_session". No entanto, os registros nesta tabela não pode ser associado a esse usuário porque o valor sessionid no cookie é reposto quando o redirecionamento ocorre.

Eu estou supondo que eu não sou o primeiro a encontrar esse dilema. Alguém tem uma visão sobre como resolver o problema?

Foi útil?

Solução

Update:

Depois de um pouco de testes, eu percebo que o código abaixo não responder à sua pergunta. Embora ele funciona, eo manipulador de sinal é chamado, prev_session_data se existir, não contém nenhuma informação útil.

Primeiro, uma espiada no interior no quadro sessões:

  1. Quando um novo visitante solicita uma URL do aplicativo, uma nova sessão é gerado por eles - neste ponto, eles ainda são anônimos (request.user é uma instância de AnonymousUser)
  2. .
  3. Se eles pedem uma visão que requer autenticação, eles são redirecionados para a visão login.
  4. Quando a exibição de login é solicitado, ele define um valor de teste na sessão do usuário (SessionStore._session); este define automaticamente as bandeiras accessed e modified na sessão atual.
  5. Durante a fase de resposta do pedido acima, o SessionMiddleware salva a sessão atual, efetivamente criando uma nova instância Session na tabela de django_session (se você estiver usando as sessões de backup de banco de dados padrão, fornecidas pela django.contrib.sessions.backends.db). O id da nova sessão é salvo no cookie settings.SESSION_COOKIE_NAME.
  6. Quando o usuário digita seu nome de usuário e senha e envia o formulário, eles são autenticados. Se a autenticação for bem sucedida, o método login de django.contrib.auth é chamado. login verifica se a sessão atual contém uma identificação de usuário; se isso acontecer, e o ID é o mesmo que o ID do usuário logado, SessionStore.cycle_key é chamado para criar uma nova chave de sessão, mantendo os dados da sessão. Caso contrário, SessionStore.flush é chamado, para remover todos os dados e gerar uma nova sessão. Ambos os métodos devem eliminar a sessão anterior (para o usuário anônimo), e SessionStore.create chamada para criar uma nova sessão.
  7. Neste ponto, o usuário é autenticado, e eles têm uma nova sessão. Sua ID é salvo na sessão, juntamente com a infra-estrutura usada para autenticá-los. O middleware sessão guarda estes dados para o banco de dados e salva seu novo ID de sessão em settings.SESSION_COOKIE_NAME.

Então você vê, o grande problema com a solução anterior é pela create tempo é chamado (passo 5), ID da sessão anterior é muito longe. Como outros apontaram , isso acontece porque uma vez que o cookie de sessão expira, é silenciosamente eliminado pelo navegador.

Com base na Alex de Gaynor sugestão , Eu acho que eu vim com uma outra abordagem, que parece estar a fazer o que está pedindo, mas é ainda um pouco áspero em torno das bordas. Basicamente, eu uso um cookie segundo longa vida "auditoria", para espelhar o ID da sessão, e alguns middleware para verificar a presença desse cookie. Para qualquer pedido:

  • Se nem o cookie de auditoria nem a exist cookie de sessão, este é provavelmente um novo usuário
  • se o cookie existe auditoria, mas o cookie de sessão não faz, este é provavelmente um usuário cuja sessão caducado
  • Se existirem as duas cookies, e têm o mesmo valor, esta é uma sessão ativa

Aqui está o código até agora:

sessionaudit.middleware.py :

from django.conf import settings
from django.db.models import signals
from django.utils.http import cookie_date
import time

session_expired = signals.Signal(providing_args=['previous_session_key'])

AUDIT_COOKIE_NAME = 'sessionaudit'

class SessionAuditMiddleware(object):
    def process_request(self, request):
        # The 'print' statements are helpful if you're using the development server
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
        audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
        if audit_cookie is None and session_key is None:
            print "** Got new user **"
        elif audit_cookie and session_key is None:
            print "** User session expired, Session ID: %s **" % audit_cookie
            session_expired.send(self.__class__, previous_session_key=audit_cookie)
        elif audit_cookie == session_key:
            print "** User session active, Session ID: %s **" % audit_cookie

    def process_response(self, request, response):
        if request.session.session_key:
            audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
            if audit_cookie != request.session.session_key:
                # New Session ID - update audit cookie:
                max_age = 60 * 60 * 24 * 365  # 1 year
                expires_time = time.time() + max_age
                expires = cookie_date(expires_time)
                response.set_cookie(
                    AUDIT_COOKIE_NAME,
                    request.session.session_key,
                    max_age=max_age,
                    expires=expires,
                    domain=settings.SESSION_COOKIE_DOMAIN,
                    path=settings.SESSION_COOKIE_PATH,
                    secure=settings.SESSION_COOKIE_SECURE or None
                )
        return response

audit.models.py :

from django.contrib.sessions.models import Session
from sessionaudit.middleware import session_expired

def audit_session_expire(sender, **kwargs):
    try:
        prev_session = Session.objects.get(session_key=kwargs['previous_session_key'])
        prev_session_data = prev_session.get_decoded()
        user_id = prev_session_data.get('_auth_user_id')
    except Session.DoesNotExist:
        pass

session_expired.connect(audit_session_expire)

settings.py :

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'sessionaudit.middleware.SessionAuditMiddleware',
    ...
)

INSTALLED_APPS = (
    ...
    'django.contrib.sessions',
    'audit',
    ...
)

Se você estiver usando isso, você deve implementar uma visão de logout personalizado, que exclui explicitamente o cookie de auditoria quando o usuário fizer fora. Além disso, eu sugiro usar assinou-os cookies do Django middleware (mas você provavelmente já está fazendo isso, não é?)

OLD:

Eu acho que você deve ser capaz de fazer isso usando um backend de sessão personalizado. Aqui estão algumas (não testado) código de exemplo:

from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.db.models import signals

session_created = signals.Signal(providing_args=['previous_session_key', 'new_session_key'])

class SessionStore(DBStore):
    """
    Override the default database session store.

    The `create` method is called by the framework to:
    * Create a new session, if we have a new user
    * Generate a new session, if the current user's session has expired

    What we want to do is override this method, so we can send a signal
    whenever it is called.
    """

    def create(self):
        # Save the current session ID:
        prev_session_id = self.session_key
        # Call the superclass 'create' to create a new session:
        super(SessionStore, self).create()
        # We should have a new session - raise 'session_created' signal:
        session_created.send(self.__class__, previous_session_key=prev_session_id, new_session_key=self.session_key)

Salvar o código acima de ums 'customdb.py' e acrescentar que para seu projeto Django. Em seu settings.py, conjunto ou substituir 'SESSION_ENGINE' com o caminho para o arquivo acima, por exemplo:.

SESSION_ENGINE = 'yourproject.customdb'

Então em seu middleware, ou models.py, fornecer um manipulador para o sinal 'session_created', assim:

from django.contrib.sessions.models import Session
from yourproject.customdb import session_created

def audit_session_expire(sender, **kwargs):
    # remember that 'previous_session_key' can be None if we have a new user
    try:
        prev_session = Session.objects.get(kwargs['previous_session_key'])
        prev_session_data = prev_session.get_decoded()
        user_id = prev_session_data['_auth_user_id']
        # do something with the user_id
    except Session.DoesNotExist:
        # new user; do something else...

session_created.connect(audit_session_expire)

Não se esqueça de incluir o aplicativo que contém o models.py em INSTALLED_APPS.

Outras dicas

SESSION_COOKIE_AGE = 1500 # 25 minutos

Coloque isso em suas configurações e que deve cuidar disso e expirar a sessão.

Eu não sei sobre Django, mas você pode, simplesmente crie um cookie não persistente, que armazena a última vez que o acesso a uma página em seu site (você atualizar o cookie em cada carregamento da página)

Então, em sua página de login, você pode verificar se o usuário tem o seu cookie, mas nenhuma sessão e, em seguida, você sabe que a sessão do usuário provavelmente expirou. Desde que você tem a hora do último acesso a uma página em seu site, você também pode calcular, em função da duração da sessão, se ele expirou.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top