How to check which user is logged in with Django? - django

I am currently working on a website, and I wanted to know how do I check which user is logged in. Just to clarify I am using the Django built in models from django.contrib.auth.models import User to do my login, logout etc. What I don't know how to do is check which user is logged in, I know the method
if user.is_authenticated:
# Other code goes here
But this method only checks weather the user is logged in not which user is logged in?

You can find info about the logged user in the request.user method
Here an example if you want to know the username:
username = request.user.username

If you make use of the AuthenticationMiddleware [Django-doc] (this is the default if you create a new project), then this middleware will add a .user attribute [Django-doc] to the request. This is a lazy loaded user model object, or the AnonymousUser [Django-doc] if the user has not logged in.
But if tyhe user thus has logged in, this is a user model object just like any other. You thus can access fields, methods, etc. from that object, and use it when you create an object to let a ForeignKey refer to that user.
If you for example use the default User model [Django-doc], then you can access attributes like request.user.first_name, request.user.last_name, request.user.username, etc.

Related

How can I get the username of the logged in user in Django?

I'M new to Django, looking to get first name and last name of the logged-in user in Django,
login method am using LDAP authentication.
when i login as admin i was able to see the LDAP user in User information tab.
Tried request.user.first_name didn't work, is there any other method to get the details?
You can use this method to get first name, last name and all details of the logged in user.
from django.contrib.auth.models import User
first_name = User.objects.get(username=request.user).first_name
last_name = User.objects.get(username=request.user).last_name
In the same way you can get any attribute of the user. For logged in users, you have to use the keyword request.user.
There is two method in AbstractUser class, you can use this
request.user.get_full_name()
request.user.get_short_name()
get_short_name will return first_name

The relation between a model and it's form in Django, and user authentication

I'm migrating something from an old PHP/apache server to Django. I'm a bit stumped with the 'ModelForm'.
As far as I understand, a "Model" is the abstraction for persistent elements in my website/server - specifically this is something stored physically, say in a database, and defines the fields (read columns) in the DB.
I started moving the authentication part of the site, and discovered models, and specifically the User model (I made an empty User inheriting AbstractUser just in case I will ever need to extend things). Now I want to create a simple two field form, to authenticate login.
The form:
Username (which is a field of User, by default)
Password (Which is not).
Even the 'Username' needs a redefinition in the model form. So my questions:
What is the advantage of the model form (over just a form)? - seems like you're redefining fields anyway, and obviously sometimes adding fields on top of the model.
Specifically for authentication, I probably need to store my salted hash associated with the user somehow, compare my password using that and retrieve the user object. This is something I find very hard to find in the Django docs - they just have too much written on authentication, and not one full code example. Do I put this in the "validate" method of form, retrieving there an object and storing it in a session or something?
If there is a deeper relation between a model form and the associated model, I would like to know as well.
Simple django forms and modelforms have quite differences.
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
The above example illustrates that you don't have to write any form field in here. The model form will itself create a form which is based on the attributes provided in the model ('Article' in this example).
If you create a simple django form then it would be something like:
class ArticleForm(forms.Form):
some_field = forms.CharField(some_attrs)
...
The django User model provides you everything you need for authentication. When you want to create users just import django.contrib.auth.models.User and use create method to create objects. Then when you want to authenticate a user use authenticate method.
from django.contrib.auth import authenticate, login
def user_login(request):
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
# after authentication login the user or set cookies or modify the session or some other action can be taken
return HttpResponse("Some response or use render for html page")
username and password will be coming from your post request.
If you want to extend default Django user model you can use django user model as onetoonefield in your extended model.
class AppUser(models.Model):
user = models.OneToOneField(User)
... # other custom fields

Change username for authenticated user in django User model

After authentification with social auth plugin, plugin create new user with not beauty usernames like sergey.kostin.345, I know that some users has a nice shorturls on the social media platforms and its ok for default behavior but I want to give user ability to change user names. As far as I understand django auth system does not let me to change User.username field by using methods. I also tried to change this field by using this code, but it seems to be ignoring in django.
owner = User.objects.get (id=request.user.id)
owner.username = newusername
owner.save()
owner is authenticated user
That would work, but there's no need to get the user again. request.user is already the user object.
owner = request.user
owner.username = newusername
owner.save()

Saving a registered user to my database model with form submission

I am using django-registration and i can't figure out how to save the user to my database model after the user hits submit. the information in the form needs to have the user with it.
how do I access the user model, is it with requestcontext? in my views.py file?
So the user has already registered, and logged in? request.user should contain the current user, if I'm remembering correctly.

How to force a user logout in Django?

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?
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:
This solution can only be used with a database session engine. In other situations (cache, file, cookie) the Session model would not be used.
When the number of sessions and users in database grows, this becomes quite inefficient.
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 a 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 a 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:
1. store in the session the last login date
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)
2. request a force logout for a user
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()
3. implement the check on access
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
Be aware of the performance implication of storing an extra field for your users. Using model inheritance will add an extra 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()
I needed something similar in my app. In my case, if a user was set to inactive, I wanted to make sure if the user was already logged in that they will be logged out and not able to continue to use the site. After reading this post, I came to the following solution:
from django.contrib.auth import logout
class ActiveUserMiddleware(object):
def process_request(self, request):
if not request.user.is_authenticated:
return
if not request.user.is_active:
logout(request)
Just add this middleware in your settings and off you go. In the case of changing passwords, you could introduce a new field in the userprofile model that forces a user to logout, check for the value of the field instead of is_active above, and also unset the field when a user logs in. The latter can be done with Django's user_logged_in signal.
Perhaps, a bit of middleware that references a list of users who have been forced to log out. Next time the user tries to do anything, log them out then, redirects them, etc.
Unless of course, they need to be logged out immediately. But then again, they wouldn't notice until they next tried to make a request anyway, so the above solution may just work.
This is in response to Balon's query:
Yes, with around 140k sessions to iterate through I can see why Harold's answer may not be as fast as you may like!
The way I would recommend is to add a model whose only two properties are foreign keys to User and Session objects. Then add some middleware that keeps this model up-to-date with current user sessions. I have used this sort of setup before; in my case, I borrowed the sessionprofile module from this Single Sign-On system for phpBB (see the source code in the "django/sessionprofile" folder) and this (I think) would suit your needs.
What you would end up with is some management function somewhere in your code like this (assuming the same code names and layout as in the sessionprofile module linked above):
from sessionprofile.models import SessionProfile
from django.contrib.auth.models import User
# Find all SessionProfile objects corresponding to a given username
sessionProfiles = SessionProfile.objects.filter(user__username__exact='johndoe')
# Delete all corresponding sessions
[sp.session.delete() for sp in sessionProfiles]
(I think this will also delete the SessionProfile objects, as from what I recall, Django's default behaviour when an object referenced by a ForeignKey is deleted is to cascade it and also delete the object containing the ForeignKey, but if not then it is trivial enough to delete the contents of sessionProfiles when you are done.)
You can also use direct django function to do that, it will update and logs out all other sessions for the user, except the current one.
from django.contrib.auth import update_session_auth_hash
update_session_auth_hash(self.request, user)
Docs for update_session_auth_hash here.
As Tony Abou-Assaleh, I also needed to log out users who were set to inactive, so I started by implementing his solution. After some time I found out that the middleware is forcing a DB query on all requests (to check if the user was blocked), and thus hurts performance on pages that doesn't require login.
I have a custom user object and Django >= 1.7, so what I ended up doing is overriding its get_session_auth_hash function to invalidate the session when the user is inactive. A possible implementation is:
def get_session_auth_hash(self):
if not self.is_active:
return "inactive"
return super(MyCustomUser, self).get_session_auth_hash()
For this to work, django.contrib.auth.middleware.SessionAuthenticationMiddleware should be in settings.MIDDLEWARE_CLASSES
As others stated, you can iterate over all sessions in DB, decode all of them, and delete those belonging to that user. 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:
django-qsessions (based on django's db, cached_db session backends)
django-user-sessions (based on django's db session backend)
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.
from django.contrib.sessions.models import Session
deleting user session
[s.delete() for s in Session.objects.all() if s.get_decoded().get('_auth_user_hash') == user.get_session_auth_hash()]
Even I faced this issue. Few spammers from India keep posting about those Baba and Molvi for love solutions.
What I did is at the time of posting just inserted this code:
if request.user.is_active==False:
return HttpResponse('You are banned on the site for spaming.')