Custom User Model - Group authorization

Django 4.1.7
Good afternoon, I need help please.

I’ve created a custom user model inherit of AbstractUser:

class User(AbstractUser):
...
 dui = models.CharField(...)
...

I created a group (via Django admin) called “SuperUser” that is like an admin user (all permissions granted) and another group called “BasicUser” that only can View models.

From superuser account I created another user “basic” and assigned the group “BasicUser”. But, when I login to django panel with “basic” account, it says “You don’t have permission to view or edit anything”.

I did this stuff:
print(user.has_perm(‘BasicUser’)) → False
print(user.get_group_permissions()) → set()
print(user.get_all_permissions()) → set()

Any idea why permissions are not inherited from the group that the user is assigned?

Connecting to the admin requires that either the is_superuser or is_staff attribute be set on that user. (Or, it requires that the AdminSite class be overridden to allow for non-is_staff users to use it.)

Regarding those print statements, we’d need to see a lot more detail about how you have permissions and groups defined and assigned.

is_staff attribute is True, I managed it from django panel administration. Groups were created via Django administration. In DB it seems that everything is fine but I don’t know why authorization doesn’t work with groups is not working.

Thank you for your quick response

Please show that you have the groups and permissions properly defined and assigned as you expect them to be. Also please show your AUTH_USER_MODEL setting to show that you are using your User model as the system user model.

user = User.objects.get(username='TestBasic')
print(user.groups.values_list('name', flat=True)) ->  <QuerySet ['BasicUser']>

group_permissions = Group.objects.get(name='BasicUser').permissions.all() 
print(group_permissions) -> <QuerySet [<Permission: blackportal | despiece | Can view despiece>, <Permission: blackportal | entity | Can view entity> ... more ...>

settings.py (My app’s name is blackportal):

AUTH_USER_MODEL = 'blackportal.User'

This isn’t correct. The has_perm function expects a permission to be supplied, not a Group name. (See User.has_perm)

For the other two function calls, the only other thing I can think of off-hand is to verify that is_active is True.

print(user.is_active) -> True
print(user.has_perm('blackportal.view_icon')) -> False (it's supossed to be true) 

I’m sure there’s an explanation for this, but I’m drawing a blank as to what to check next. There are a number of different things that it could be, but we’ve already covered the likely possibilities. (Side note: You mention Django 4.1.7 - what version of Python are you using? Are you using any third-party packages that override or modify any of User, Group, or Permission?)

At a minimum, I’d probably want to look at the complete User model, any custom managers being used, any signals attached to any of the referenced models, the INSTALLED_APPS setting, and a dump data of User, Group, Permission, and the GroupPermission join table. (I realize this may not be practical, but mostly what I’d be trying to do would be to recreate this in my lab to see if I’m getting similar results.)

I’m using python 3.11.1 and of course, i can give you all that you need.

Installed Apps:

INSTALLED_APPS = [
    "corsheaders",
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blackportal',
    'rest_framework',
    'django_filters',
    'drf_yasg',
    'rest_framework_simplejwt'
],
AUTHENTICATION_BACKENDS = [
'blackportal.controllers.user.UserController.EmailUsernameAuthenticationBackend'
]

User Model:

class User(AbstractUser):
    code = models.CharField(max_length=12, unique=True)
    role = models.CharField(max_length=50,null=True,blank=True, default=None)
    name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=150)
    username = models.CharField(max_length=150, unique=True)
    dui = models.CharField(max_length=20, unique=True)
    short_name = models.CharField(max_length=50, unique=True)
    position = models.CharField(max_length=100)
    email = models.EmailField(max_length=75, unique=True)
    password = models.TextField()
    system_access = models.TextField(null=True, blank=True, default=None)
    deleted = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    deleted_at = models.DateTimeField(blank=True, null=True)
    
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']

Others:

class EmailUsernameAuthenticationBackend(object):
    @staticmethod
    def authenticate(request, username=None, password=None):
        try:
            user = User.objects.get(
                Q(username=username)
            )

        except User.DoesNotExist:
            return None

        if user and check_password(password, user.password):
            return user

        return None

    @staticmethod
    def find_user(username=None):
        try:
            return User.objects.get(
                Q(username=username)
            )
        except User.DoesNotExist:
            return 'User not found'

Login View:

class LoginApiView(APIView):
    def post(self,request):
        login_data = request.data
        userdata = login_data.get('username','')
        password = login_data.get('password','')
        user_auth = AuthT.authenticate(request,username=userdata, password=password)
        print(user_exists)
            
            if user_auth:
                login_serializer = self.serializer_class(data=request.data)
                if login_serializer.is_valid():
                    print(login_serializer.validated_data)
                    return Response({
                    "access_token":login_serializer.validated_data.get('access'),
                    "refresh_token":login_serializer.validated_data.get('refresh')
                },status=status.HTTP_200_OK)
                else:
                    return Response({"error":login_serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
                
            else:
                return Response({"message":"Invalid credentials"}, status=status.HTTP_400_BAD_REQUEST)
       

CutomTokenSerializer:

class CustoMObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['email'] = user.email
        token['code'] = user.code
        token['dui'] = user.dui
        token['role'] = user.role
        token['short_name'] = user.short_name
        token['username']  = user.username
   
        return token

This is my code for authentication and everything related to user administration (I think CRUD operations are not necessary, i guess )

I really appreciate your help

Ok, this explains a lot.

Your authentication back end doesn’t implement the has_perm, get_group_permissions, and get_all_permissions methods - at least not from what you’re showing here. Your authentication backend either needs to inherit from ModelBackend overriding the methods that don’t apply, or you need to implement these methods yourself in your backend.

See the docs at Customizing authentication in Django | Django documentation | Django for more details. I also suggest you read the source code for the ModelBackend.

Finally!!!, it works now. I really appreciate your help, thank you very much!!