In my Django app under certain conditions I want to be able to force users to log out by a username. Not necessarily the current user who is logged in, but another user. So, the request method in my view doesn't have any session information about the user that I want to logout.
I am familiar with django.auth and with auth. logout method, but it takes request as an argument. Is there a "Django-way" to log the user out if all I have is the username? Or do I have to roll my own logout SQL?
To log out a user who has been logged in via django.contrib.auth.login() , use django.contrib.auth.logout() within your view. It takes an HttpRequest object and has no return value. Example: from django.contrib.auth import logout def logout_view(request): logout(request) # Redirect to a success page.
Django comes with a user authentication system. It handles user accounts, groups, permissions and cookie-based user sessions. This section of the documentation explains how the default implementation works out of the box, as well as how to extend and customize it to suit your project's needs.
Update:
Since Django 1.7, users are automatically logged-out when their password changes. On each request, the current password hash is compared to the value saved in their session and if doesn't match, the user is logged-out.
So, a simple password update has the effect of logging the user out. You can then disable the account for login, or advise them to use the password reset feature to set a new password and log in again.
Original:
I don't think there is a sanctioned way to do this in Django yet.
The user id is stored in the session object, but it is encoded. Unfortunately, that means you'll have to iterate through all sessions, decode and compare...
Two steps:
First delete the session objects for your target user. If they log in from multiple computers they will have multiple session objects.
from django.contrib.sessions.models import Session from django.contrib.auth.models import User # grab the user in question user = User.objects.get(username='johndoe') [s.delete() for s in Session.objects.all() if s.get_decoded().get('_auth_user_id') == user.id]
Then, if you need to, lock them out....
user.is_active = False user.save()
Although Harold's answer works in this specific case, I can see at least two important issues with it:
Session
model would not be used.To solve those issues, I suggest you take another approach at the problem. The idea is to store somewhere the date when the user was logged in for a given session, and the last time you requested an user to be logged out.
Then whenever someone access your site, if the logged in date is lower than the log out date, you can force-logout the user. As dan said, there's no practical difference between logging out an user immediately or on his next request to your site.
Now, let's see a possible implementation of this solution, for django 1.3b1. In three steps:
Fortunately, Django auth system exposes a signal called user_logged_in
. You just have to register that signals, and save the current date in the session. At the bottom of your models.py
:
from django.contrib.auth.signals import user_logged_in from datetime import datetime def update_session_last_login(sender, user=user, request=request, **kwargs): if request: request.session['LAST_LOGIN_DATE'] = datetime.now() user_logged_in.connect(update_session_last_login)
We just need to add a field and a method to the User
model. There's multiple ways to achieve that (user profiles, model inheritance, etc.) each with pros and cons.
For the sake of simplicity, I'm gonna use model inheritance here, if you go for this solution, don't forget to write a custom authentication backend.
from django.contrib.auth.models import User from django.db import models from datetime import datetime class MyUser(User): force_logout_date = models.DateTimeField(null=True, blank=True) def force_logout(self): self.force_logout_date = datetime.now() self.save()
Then, if you want to force logout for user johndoe
, you just have to:
from myapp.models import MyUser MyUser.objects.get(username='johndoe').force_logout()
Best way here is to use a middleware as dan suggested. This middleware will access request.user
, so you need to put it after 'django.contrib.auth.middleware.AuthenticationMiddleware'
in your MIDDLEWARE_CLASSES
setting.
from django.contrib.auth import logout class ForceLogoutMiddleware(object): def process_request(self, request): if request.user.is_authenticated() and request.user.force_logout_date and \ request.session['LAST_LOGIN_DATE'] < request.user.force_logout_date: logout(request)
That should do it.
Notes
JOIN
. Using user profiles will add an extra query. Modifying directly the User
is the best way performance wise, but it is still a hairy topic.If you deploy that solution on an existing site, you will probably have some trouble with existing sessions, which won't have the 'LAST_LOGIN_DATE'
key. You can adapt a bit the middleware code to deal with that case :
from django.contrib.auth import logout class ForceLogoutMiddleware(object): def process_request(self, request): if request.user.is_authenticated() and request.user.force_logout_date and \ ( 'LAST_LOGIN_DATE' not in request.session or \ request.session['LAST_LOGIN_DATE'] < request.user.force_logout_date ): logout(request)
In django 1.2.x, there is no user_logged_in
signal. Fall back to overriding the login
function:
from django.contrib.auth import login as dj_login from datetime import datetime def login(request, user): dj_login(request, user) request.session['LAST_LOGIN_DATE'] = datetime.now()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With