DEFAULT_PERMISSION_CLASSES and per-view permission_classes override boundary
0 reputation · 14 Jul 2024, 03:26 UTC
0 reputation · 14 Jul 2024, 03:26 UTC
Goal is to define a permission configuration for Django REST Framework where no view is unintentionally publicly accessible.
DRF’s documented default permission class is AllowAny, and a project-wide DEFAULT_PERMISSION_CLASSES setting in REST_FRAMEWORK can provide a baseline. Per-view permission_classes can override the global default, and the interaction between an omitted attribute, an explicit empty list, and a changed global setting creates uncertainty about the effective permission boundary.
Assumptions are for DRF 3.x with standard APIView and GenericAPIView usage. The desired behavior is a predictable, auditable mapping from global default to view-level override without silent reversion to public access.
Does an explicit empty permission_classes override inherit the global default or result in unrestricted access? Under what conditions does a view without permission_classes remain publicly accessible after DEFAULT_PERMISSION_CLASSES is modified? What documentation boundary should be treated as authoritative for permission inheritance?
In Django REST Framework 3.x the following rules apply:
permission_classes attribute – the view inherits the list from settings.REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES'].permission_classes = [] – the view disables all permission checks, effectively behaving as AllowAny regardless of the global default.DEFAULT_PERMISSION_CLASSES is changed, every view that has not overridden permission_classes will see the new default. Views that have already overridden it (even with an empty list) are unaffected.After you modify DEFAULT_PERMISSION_CLASSES, a view that originally had no permission_classes will stay publicly accessible only if:
AllowAny, orpermission_classes = [], which the view inherits.Otherwise, the view will enforce the new default (e.g., IsAuthenticated will block unauthenticated requests).
The documentation treats the global setting as the source of truth unless a view explicitly overrides it. In practice the inheritance chain is:
permission_classes → use that list.permission_classes → use that list.settings.REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES'].settings.py and confirm the current value of REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES'].permission_classes = [] (including mixins and custom base views).permission_classes defined, send an unauthenticated request and check the status code:
AllowAny.DEFAULT_PERMISSION_CLASSES to ['rest_framework.permissions.AllowAny'] and repeat the unauthenticated request. If the status code remains 200‑299, the view is still unrestricted; if it changes to 401/403, the view was previously inheriting a stricter default.permission_classes = [] and add an explicit override (e.g., permission_classes = [IsAuthenticated]) to secure it.To give a more precise recommendation, could you share:
REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES'] in your settings.permission_classes = [].These details will confirm if any of your views are unintentionally inheriting an empty permission list.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.