Welcome to my first tutorial on this platform. In this one i'm going to show you how to prevent a user account from having multiple sessions at the same time.
Whenever a user logs in, the previous sessions is deleted.
This approach could be useful in subscription based apps where you want a single access for the subscribing user.
For this tutorial, We'll be using django 2.0.4 and its middleware framework.
The middleware is simply the middle guy or lady in between django's request/response processing. Django has some middlewares which we already use in our projects by default.
The middleware framework is what we're going to use to check if the user has an existing session on our application whenever a user makes a request.
If a session, exists, it deletes it and assigns the new session from the request as the current session.
Note: "Django stores session data in the "django_session" table, so deleting a user's session from the database has the same effect as logging out a user."
Too much talk, right? OK let's just code.
Ermm... one more thing. All the code below should be stored in one app. I believe you know this but there's no harm in stating the obvious sometimes.
Create an app in your django project called 'accounts' and follow this tutorial.
We need to create a model to store the list of users that are currently logged into our app
from django.conf import settings User = settings.AUTH_USER_MODEL # Model to store the list of logged in users class LoggedInUser(models.Model): user = models.OneToOneField(User, related_name='logged_in_user') # Session keys are 32 characters long session_key = models.CharField(max_length=32, null=True, blank=True) def __str__(self): return self.user.username
We created a
user field with a
OneToOneField so that a
user can only have one entry in the table. In simple terms, this uniquely identifies a user in the table. In simpler terms, there are no duplicate entries for a user in the table. In the simplest term ['insert yours here']. The
related_name attribute is used to give a more friendly name for reverse relationship to the
User model (you'll see soon).
session_key would be used to store the
session_key. So sorry if you were expecting a simpler explanation. Those times are past.
Create a new file, called
signals.py in your app directory. Signals are used to broadcast events whenever an action occurs in our app.
For our app, we need to know whenever a user logs in and logs out. With the help of signals, we can know this and perform some actions (here, insert the user to the LoggedInUser table).
# Signals that fires when a user logs in and logs out from django.contrib.auth import user_logged_in, user_logged_out from django.dispatch import receiver from accounts.models import LoggedInUser @receiver(user_logged_in) def on_user_logged_in(sender, request, **kwargs): LoggedInUser.objects.get_or_create(user=kwargs.get('user')) @receiver(user_logged_out) def on_user_logged_out(sender, **kwargs): LoggedInUser.objects.filter(user=kwargs.get('user')).delete()
We're using the inbuilt
user_logged_out signals which fires whenever a user successfully logs in and log outs respectively.
If you were wondering how we got the user' through the
kwargs, wonder no more my friend. The
user argument is always sent with the two signals mentioned above.
Add the following code in your
apps.py file to import your signals.
from django.apps import AppConfig class AccountsConfig(AppConfig): name = 'accounts' # This function is the only new thing in this file # it just imports the signal file when the app is ready def ready(self): import accounts.signals
settings.py file, update your app's name to point to exact app in
INSTALLED_APPS = [ ..... 'accounts.apps.AccountsConfig', ]
Create a file called
middleware.py in your app directory.
#Session model stores the session data from django.contrib.sessions.models import Session class OneSessionPerUserMiddleware: # Called only once when the web server starts def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # Code to be executed for each request before # the view (and later middleware) are called. if request.user.is_authenticated: stored_session_key = request.user.logged_in_user.session_key # if there is a stored_session_key in our database and it is # different from the current session, delete the stored_session_key # session_key with from the Session table if stored_session_key and stored_session_key != request.session.session_key: Session.objects.get(session_key=stored_session_key).delete() request.user.logged_in_user.session_key = request.session.session_key request.user.logged_in_user.save() response = self.get_response(request) # This is where you add any extra code to be executed for each request/response after # the view is called. # For this tutorial, we're not adding any code so we just return the response return response
request.user.logged_in_user.session_key we can use
logged_in_user here because we defined it as the related name for the
user field in your
LoggedInUser model. If we didnt do that, the reverse relationship name would be
loggedinuser which doesnt follow python's naming convention.
Finally, add this middleware we just created in your
MIDDLEWARE list in your
MIDDLEWARE = [ .... 'accounts.middleware.OneSessionPerUserMiddleware' ]
In this one we learnt how to prevent a user from having multiple sessions in your app. More like preventing bad people from streaming videos on 50 devices (50 friends and family's devices to be precise) from one subscribed account on your web app.
This tutorial was to show you how to create custom middlewares in your django app.
There are definitely other ways which might be better in achieving this. This might not be a perfect solution to your needs. The idea was just to show you how middlewares work.
Now go forth and explore!!
Thanks for reading.
You know what to do after watching this video, right?
OK, let me just state the obvious once more. Hit the 'subscribe' button then click the bell icon. Thanks once again for reading.