I'm working on a class generator of sorts. I want to be able to create many children of BasePermission that are customizable using a required_scopes attribute. This is what I have so far.
from rest_framework.permissions import BasePermission
class ScopedPermissionMeta(type(BasePermission)):
def __init__(self, name, bases, attrs):
try:
required_scopes = attrs['required_scopes']
except KeyError:
raise TypeError(f'{name} must include required_scopes attribute.')
required_scopes_list = ' '.join(required_scopes)
attrs['message'] = f'Resource requires scope={required_scopes_list}'
def has_permission(self, request, _view):
"""Check required scopes against requested scopes."""
try:
requested_scopes = request.auth.claims['scope']
except (AttributeError, KeyError):
return False
return all(scope in requested_scopes for scope in required_scopes)
attrs['has_permission'] = has_permission
class ReadJwtPermission(BasePermission, metaclass=ScopedPermissionMeta):
required_scopes = ['read:jwt']
However, I do not like how the ReadJwtPermisson class (and the many more children) must specify a metaclass. Idealy I want that detail abstracted away. I want to be able to do something like:
class ScopedPermission(BasePermission, metaclass=ScopedPermissionMeta):
pass
class ReadJwtPermission(ScopedPermission):
required_scopes = ['read:jwt']
but in this situation the metaclass see's ScopedPermission and no required_scopes. Is there a way to allow the metaclass to see through this inheritance relationship?