Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check django staff user first time login in admin panel?

I am working on a django project and I am using the default auth app for authentication.
I know that there is a last_login field in user model which stores the user's last login time.

When a staff user logs in first time into the admin panel, I want to check if last_login field is none & redirect him to the change password page.

Where should I put this check?


What I have tried so far:

I have tried to use a custom login form and override the default confirm_login_allowed method on it, but it seems like I can only raise a validation error to block login attempt using these.

I also tried using django.contrib.auth.signals.user_logged_in Signal but that also does not allow me to return a redirect response when last_login is None.

I want to know how I can return a redirect response after the user has been authenticated.

like image 473
Mohan Avatar asked Dec 15 '17 06:12

Mohan


People also ask

How can I see the username as logged in Django?

First make sure you have SessionMiddleware and AuthenticationMiddleware middlewares added to your MIDDLEWARE_CLASSES setting. request. user will give you a User object representing the currently logged-in user.

How do I find my Django username and password?

from django.contrib.auth import authenticate, login def my_view(request): username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) # Redirect to a success page. ... else: # Return an 'invalid ...

What is staff status in Django admin?

staff. - A user marked as staff can access the Django admin. But permissions to create, read, update and delete data in the Django admin must be given explicitly to a user. By default, a superuser is marked as staff.


2 Answers

Customise Django admin using AdminSite and use login_form attribute to give the custom login form for the Admin login page.

admin.py

class MyAdminSite(AdminSite):
    login_form = CustomAdminLoginForm

admin_site = MyAdminSite(name='myadmin')
admin_site.register(User)
admin_site.register(Group

urls.py

When overriding the Admin we have to get rid of Django default admin

from app.admin import admin_site

url(r'^admin/', admin_site.urls)

forms.py

AuthenticationForm have the confirm_login_allowed method use this to grant permission to login in or not login in.

class CustomAdminLoginForm(AuthenticationForm):
    def confirm_login_allowed(self, user):
        if user.last_login:
            raise ValidationError(mark_safe('Hey first time user please reset your password here... <a href="/test">test</a>'), code='inactive')

Note: There is lot of edge cases you have to consider for this approach.

  1. What if user not set the password in the first time and how you're going to handle second attempt..? This time last_long not None. Although date_joined comes rescue. last_login == date_joined
  2. But What if the user not set the password in first day and comes next day ?

Edit:

You can use signal to check the logged in user and apply the config_login_allowed logic here...?

from django.contrib.auth.signals import user_logged_in


def change_password_first_time(sender, user, request, **kwargs):
    # Your business logic here...

user_logged_in.connect(change_password_first_time)
like image 90
Raja Simon Avatar answered Sep 27 '22 17:09

Raja Simon


Django admin is not that configurable. You should hook into its internal views. Login/logout views are inside Django AdminSite class (the one you usually access by admin.site). My implementation is a bit hacky but small:

Paste at the top of urls.py

from django.contrib import admin
from django.contrib.admin import AdminSite
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

class MyAdminSite(AdminSite):
    def login(self, request, extra_context=None):
        new_user = False
        user = None

        username = request.POST.get('username')  # Hack to find user before its last_login set to now.
        if username:
            user = User.objects.filter(username=username).first()
            if user:
                new_user = user.last_login is None

        r = super(MyAdminSite, self).login(request, extra_context)

        if new_user and request.user == user and isinstance(r, HttpResponseRedirect):  # Successful logins will result in a redirect.
            return HttpResponseRedirect(reverse('admin:password_change'))
        return r

admin.site = MyAdminSite()

If you want a cleaner solution I suggest to use a boolean inside user model instead of relying on last_login so you could just check request.user instead of my hack into request.POST.

You could read AdminSite.login and django.contrib.auth.views.login to see what is actually happening inside Django.

like image 27
Arman Ordookhani Avatar answered Sep 27 '22 18:09

Arman Ordookhani