Gonzalo Dambra
Gonzalo Dambra

Reputation: 980

Django 2.1.7 get session key

I know this is a possible duplicate post, I found a solution for this, but those posts are from older versions of Django and I can't get the new syntaxis. Could someone give me a tip please?

I'm trying to prevent users to use the same account simultaneously. So when someone log in an account, if the user and pass are ok, I'm iterating the django_session table in order to find if theres any other session with the same account, if yes, close this session and start the last one.

After auth.authenticate(blah blah):

    if user is not None:
                # Checks if there's any other active session with the same account
                for session in Session.objects.filter(session_key=request.session.session_key): # //aq
                    data = session.get_decoded()
                    print(data.get('_auth_user_id', None))
                    if data.get('_auth_user_id', None) == str(user.id):
                    session.delete()

But something is not working with this syntaxis. I can't get the session user's ID. When a user logs in I'm using request.session['logueado'] = user.id and auth.login(request, user).

This should be like a "last to log in wins" system.

EDIT: Whole code:

def login(request):
    if 'logged' in request.session:
        return redirect(main)
    if request.method == "GET":
        form = LoginForm
        return render(request, "login.html", {"form": form})
    if request.method == "POST":
        print('POST method.')
        form = LoginForm(request.POST)
        if form.is_valid():
            print('Valid form.')
            user_name = form.cleaned_data.get('username')
            user_pass = form.cleaned_data.get('password')
            user = auth.authenticate(username=user_name, password=user_pass)
            if user is not None:
                for session in Session.objects.filter(session_key=request.session.session_key):
                    print('Hello')
                    data = session.get_decoded()
                    if data.get('_auth_user_id', None) == request.session.session_key:
                        print('Same account in more than 1 session.')
                        session.delete()
                #------------------------------------------------------------------
                request.session['logged'] = user.id
                print(request.session['logged'])
                auth.login(request, user)
                request.session.set_expiry(0) #
                return redirect(main)
            else:
                return render(request, "loginError.html", {"form": form})

EDIT: Definitive solution: (Thank you Daniel Roseman!)

user = auth.authenticate(username=user_name, password=user_pass)
if user is not None:
    # Checks if there's another session with the same acc
    Sessions = Session.objects.all()
    for row in Sessions:
        print(row.get_decoded().get('_auth_user_id'))
            print(user.id)
            if str(row.get_decoded().get("_auth_user_id")) == str(user.id):
                print('Same sessions')
                row.delete()

    request.session['logged'] = user.id

Upvotes: 0

Views: 1735

Answers (2)

Mohammad Javad Naderi
Mohammad Javad Naderi

Reputation: 506

As Daniel Roseman answered, you can iterate over all sessions in DB, decode all of them, and delete those you want. But it's slow, particularly if your site has high traffic and there are lots of sessions.

If you need a faster solution, you can use a session backend that lets you query and get the sessions of a specific user. In these session backends, Session has a foreign key to User, so you don't need to iterate over all session objects:

Using these backends, deleting all sessions of a user can be done in a single line of code:

user.session_set.all().delete()

Disclaimer: I am the author of django-qsessions.

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 599600

Your code is based on all sorts of false assumptions.

Session keys don't in any way map to login IDs. And they are unique: each client will have a different key, even if they're logged in as the same user. What's more, the session is explicitly flushed when a user logs in, so they will get a new key.

In other words, the only way to do something like this would be to iterate over all sessions in the database, decode them, and check if their _auth_user_id item is equal to the user ID.

Upvotes: 1

Related Questions