Django rest auth user_logged_in signal
Asked Answered
T

5

5

I have a django rest app using django rest auth. I'm trying to log something everytime a user log in using signals.

I've searched on the web on how to use signals and I haven't found any interesting material on how to make it work. I think the problem may be with allauth signals. Is there any problem with the following configuration?

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'
Tessera answered 8/4, 2017 at 20:59 Comment(0)
P
10

Here's how I solved it using 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)
Polycotyledon answered 25/2, 2018 at 6:17 Comment(1)
It worked for me as well. Thanks. However, better also mention that 'rest_framework_jwt.authentication.JSONWebTokenAuthentication' needs to be added to the REST_FRAMEWORK variable in settings.pyAlexisaley
L
2

It seems that Django Rest Framework doesn't emit user_logged_in signal when token-based authentication is configured: https://github.com/encode/django-rest-framework/issues/3869

Longsome answered 20/9, 2017 at 23:48 Comment(0)
W
2

For future googlers. The OP's original question was that he wanted to log something everytime a user logs in when using rest_auth. You would expect a signal to be emitted by rest_auth for something like this but rest_auth does different things depending on the type of login. For a session login, rest_auth calls into django's normal login routines and a signal does get emitted. But for token-based authentication, rest_auth creates the token and returns it and there is no call into django proper and no signal is emitted. Here's the rest_auth login code

To get the behavior you want, you have to override rest_auth's default token handler (it's straightforward) so you know when a token gets created and then log the event however you want.

In django's settings.py file add:

REST_AUTH_TOKEN_CREATOR = '<your_dotted_project_path>.create_login_token'

In some file in your project:

# 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
Werbel answered 10/3, 2020 at 23:5 Comment(0)
M
1

For some strange reason, this doesn't seem to work when placed in signals.py, this implementation of signals.py works fine for every part of project except for allauth(I had my personal experience too). Check this github issueshttps://github.com/pennersr/django-allauth/issues/347

For some strange reason moving this code(signals.py) into models.py of the same app will work.

# 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))
Maximamaximal answered 8/4, 2017 at 21:59 Comment(5)
Am I missing some configuration stuff?Tessera
all looks good for me, can you just make sure logger for users app is configired in settings (just to make sure ), otherwise I dont see any reason why it shouldnt workMaximamaximal
place this in models.py , and restart the local server, it should workMaximamaximal
I already tried to move the code to model.py and it doesn't work. I think the problem may be in allauth configuration beacuse I tried to debug it and it never hit any of the receivers... Then I tried to add request_finished receiver and that worked. So I think the problem is with allaurh signals, but the documentation is so poor.Tessera
Since the update to dajngo 3.2, this regression has been solved. Now it is working as desired when placing these functions into a signal.py either.Semang
I
1

It doesn't pick up from signals.py for some strange reason. However, you can still maintain the separation of concerns using the following. This worked for me while still keeping the signal logic away from my models.

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
Impale answered 12/6, 2020 at 9:37 Comment(1)
Since the update to dajngo 3.2, this regression has been solved. Now it is working as desired when placing these functions into a signal.py either.Semang

© 2022 - 2024 — McMap. All rights reserved.