11

I would like to implement a 2nd admin site which provides a subset of feature of the primary admin site. That's possible and described in the Django docs

However, I would like to limit access on the primary admin site. Some users can access the 2ndary site but not the primary site.

In order to implement that feature, I would like these users not to be in the staff (is_staff=False) and rewrite the AdminSite.has_permission

class SecondaryAdminSite(AdminSite):
    
    def has_permission(self, request):
        if request.user.is_anonymous:
            try:
                username = request.POST['username']
                password = request.POST['password']
            except KeyError:
                return False
            try:
                user = User.objects.get(username = username)
                if user.check_password(password):
                    return user.has_perm('app.change_onlythistable')
                else:
                    return False
            except User.DoesNotExist:
                return False
        else:
            return request.user.has_perm('app.change_onlythistable')

Unfortunately, this approach doesn't work. The user can login but can't see anything in the secondary admin site.

What's wrong with this approach? Any idea how to implement this feature?

Thanks in advance

luc
  • 41,928
  • 25
  • 127
  • 172
  • Why don't you just partition your users into superusers, managers, customers etc - permission system works perfectly. – Tomasz Zieliński Oct 26 '10 at 14:43
  • @Tomasz: I am doing that too. The 2ndary admin site has a different purpose so address different type of users. I would like to avoid that they connect to the usual admin. – luc Oct 26 '10 at 14:59
  • I assume you're verifying that the correct `has_permission` is being called? Does nothing whatsoever show up on the page (i.e. it is completely blank), or is it simply hiding the admin functions? – Jordan Reiter Oct 26 '10 at 18:47
  • it says that I have no rights on this app. If I restore the is_staff on the logged user, they I can see the models. – luc Oct 26 '10 at 19:37
  • `is_staff` is required by the admin. If you have some reason why these users can't have that set to true, I think your best option is to write your own admin views. With access controls like the `has_permission` decorator you can enforce your own authorization scheme. – Paul Bissex Dec 01 '10 at 16:40

3 Answers3

5

Here's what worked for me with Django >= 3.2.

  • Create a subclass of AdminSite
  • Override the has_permission() method to remove the is_staff check.
  • Override the login_form to use AuthenticationForm.
    • AdminSite uses AdminAuthenticationForm, which extends AuthenticationForm and adds a check for is_staff.

Code

# PROJECT/APP/admin.py

from django.contrib.admin import AdminSite
from django.contrib.admin.forms import AuthenticationForm


class MyAdminSite(AdminSite):
    """
    App-specific admin site implementation
    """

    login_form = AuthenticationForm

    site_header = 'Todomon'

    def has_permission(self, request):
        """
        Checks if the current user has access.
        """
        return request.user.is_active


site = MyAdminSite(name='myadmin')

Jigarius
  • 394
  • 3
  • 16
4

I think that your approach should now be possible: http://code.djangoproject.com/ticket/14434 (closed 5 weeks ago)

However, the explicit "is_staff" check is still done in two places (apart from the staff_member_required decorator):

  • django.contrib.admin.forms.AdminAuthenticationForm.clean()

    On top of "has_permission()" you'd need to provide your non-staff AdminSite with a "login_form" that doesn't do the is_staff check, so could just subclass and adjust clean() accordingly.

  • templates/admin/base.html

    would need to be slightly customized. The div with id "user-tools" is only shown for active staff members. I'm assuming that's done because the login form also uses this template, and someone could be logged in as an active non-staff member but still should'nt see those links.

Danny W. Adair
  • 12,498
  • 4
  • 43
  • 49
  • Please let me know how you go because it's untested and I'd like to do the same at some stage :-) – Danny W. Adair Apr 07 '11 at 07:37
  • Reply to the ticket too if this is all you need to change. For extra brownie points, you could even work on the patch there and everyone benefits! :) – SmileyChris Sep 14 '11 at 05:07
  • I don't think I know enough about AdminSite to create a patch :-)... Tricky, tricky - AdminSite.login_form is an AdminAuthenticationForm but the latter doesn't yet have an attribute to go the other direction and ask "its" AdminSite (more than one could share the same login_form...) for has_permission()... That could be passed into the constructor but I don't know the consequences - getting instantiated with request (cookies) and all... The template has the same problem. On a case-by-case basis I can swap one hardcoded piece of code with another, a generic solution is harder... – Danny W. Adair Sep 14 '11 at 06:01
-1

What's wrong with this approach? Any idea how to implement this feature?

What's wrong with this approach is that permissions and groups can already provide you with what you need. There is no need to subclass AdminSite if all you need is to divide users.

This is probably why this feature is so poorly documented, IMHO

airstrike
  • 2,270
  • 1
  • 25
  • 26
  • 1
    The 2ndary site is not only a different way to manage permissions. It provides custom screens and additional features. The django admin site is great and can be highly customized. Stange that is a bit difficult to customize – luc Dec 02 '10 at 06:06