Django rest auth user_logged_in 信号

Django rest auth user_logged_in signal

我有一个使用 django rest auth 的 django rest 应用程序。 每次用户使用信号登录时,我都会尝试记录一些内容。

我在网上搜索了如何使用信号,但没有找到任何有趣的 material 如何让它发挥作用。我认为问题可能出在 allauth 信号上。下面的配置有没有问题?

signals.py

import logging

from allauth.account.signals import user_logged_in
from django.dispatch import receiver

logger = logging.getLogger(__name__)


@receiver(user_logged_in)
def login_logger(request, user, **kwargs):
    logger.info("{} logged in with {}".format(user.email, request))

apps.py

from django.apps import AppConfig


class UsersConfig(AppConfig):
    name = 'users'

    def ready(self):
        import users.signals

__init__.py

default_app_config = 'users.apps.UsersConfig'

由于某些奇怪的原因,这在 signals.py 中似乎不起作用,signals.py 的这种实现对项目的每个部分都适用,除了 allauth(我也有我的亲身经历)。检查这个 github 问题 https://github.com/pennersr/django-allauth/issues/347

出于某些奇怪的原因,将此代码 (signals.py) 移至同一应用程序的 models.py 中会起作用。

# place this in models.py
from allauth.account.signals import user_logged_in
from django.dispatch import receiver

logger = logging.getLogger(__name__)


@receiver(user_logged_in)
def login_logger(request, user, **kwargs):
    logger.info("{} logged in with {}".format(user.email, request))

配置基于令牌的身份验证时,Django Rest Framework 似乎没有发出 user_logged_in 信号:https://github.com/encode/django-rest-framework/issues/3869

这是我使用 djangorestframework-jwt==1.11.0:

解决问题的方法

settings.py

from django.contrib.auth.signals import user_logged_in

def jwt_response_payload_handler(token, user=None, request=None):
    if user and request:
        user_logged_in.send(sender=user.__class__, request=request, user=user)
    return {
        'token': token,
    }

JWT_AUTH = {
    'JWT_RESPONSE_PAYLOAD_HANDLER': jwt_response_payload_handler,
}

models.py

from django.contrib.auth.signals import user_logged_in

def login_handler(sender, user, request, **kwargs):
    print('logged in')

user_logged_in.connect(login_handler)

对于未来的谷歌员工。 OP 最初的问题是他想在用户每次使用 rest_auth 登录时记录一些东西。您可能希望 rest_auth 发出这样的信号,但 rest_auth 根据登录类型做不同的事情。对于会话登录,rest_auth 调用 django 的正常登录例程并且确实发出信号。但是对于基于令牌的身份验证,rest_auth 创建令牌并 returns 它并且没有调用 django 本身并且没有发出信号。 这是 rest_auth login code

要获得您想要的行为,您必须覆盖 rest_auth 的 default token handler(这很简单),这样您就知道令牌何时创建,然后根据需要记录事件。

在 django 的 settings.py 文件中添加:

REST_AUTH_TOKEN_CREATOR = '<your_dotted_project_path>.create_login_token'

在您项目的某个文件中:

# this is the same as the default rest_auth token handler except we
# don't throw away the 'created' part because we care whether it was
# created or just retrieved.
def create_login_token(token_model, user, serializer):
    token, created = token_model.objects.get_or_create(user=user)
    if created:
        >>> log it or emit your own signal or whatever <<<

    return token

由于某些奇怪的原因,它没有从 signals.py 接收。但是,您仍然可以使用以下方法保持关注点分离。这对我有用,同时仍然使信号逻辑远离我的模型。

signals.py

import logging

from allauth.account.signals import user_logged_in
from django.dispatch import receiver

logger = logging.getLogger(__name__)


@receiver(user_logged_in)
def login_logger(request, user, **kwargs):
    logger.info("{} logged in with {}".format(user.email, request))

models.py

from .signals import *

// Your models here

class Foo(models.Model):
    pass