1.AllowAny, IsAuthenticated, IsAdminUser, and the shipped set
A permission class answers "may this caller do this?" after authentication has already answered "who is this?". DRF ships a handful: `AllowAny` lets everything through, `IsAuthenticated` requires a signed-in user, `IsAdminUser` requires `user.is_staff` (not `is_superuser`, despite the name), and `IsAuthenticatedOrReadOnly` allows anyone to read but only signed-in users to write. `DjangoModelPermissions` maps HTTP methods onto Django's own `add`/`change`/`delete` model permissions. Every class in `permission_classes` must pass — the list is an AND, and the first failure ends the request.
Key features
- DRF's out-of-the-box `DEFAULT_PERMISSION_CLASSES` is `["rest_framework.permissions.AllowAny"]` — an endpoint you forget to protect is public, not closed
- `IsAdminUser` checks `request.user.is_staff`, not `is_superuser` — the name is misleading and the difference matters
- `SAFE_METHODS` is `("GET", "HEAD", "OPTIONS")`; `IsAuthenticatedOrReadOnly` is built entirely on that tuple
- `DjangoModelPermissions` maps `POST` → `add_*`, `PUT`/`PATCH` → `change_*`, `DELETE` → `delete_*`, and requires the view to have a `queryset` so it can find the model
- `DjangoModelPermissions` allows GET for anyone authenticated; use `DjangoModelPermissionsOrAnonReadOnly` or a custom class if reads need restricting too
- The list is AND, evaluated in order — for OR you need the `|` operator, not two entries
The shipped permission classes
- AllowAny: between anonymous caller and authenticated caller, between safe methods · GET/HEAD/OPTIONS and unsafe methods · POST/PUT/PATCH/DELETE — the default — allows every cell
- IsAuthenticatedOrReadOnly: anonymous caller, safe methods · GET/HEAD/OPTIONS — anonymous reads allowed; writes require a user
- IsAuthenticated: authenticated caller, between safe methods · GET/HEAD/OPTIONS and unsafe methods · POST/PUT/PATCH/DELETE — the whole right column, nothing on the left
- DjangoModelPermissions: authenticated caller, unsafe methods · POST/PUT/PATCH/DELETE — writes need add/change/delete; GET is unrestricted
- IsAdminUser: authenticated caller, unsafe methods · POST/PUT/PATCH/DELETE — is_staff only — the narrowest shipped class
Command
class OrderViewSet(viewsets.ModelViewSet):
queryset = Order.objects.all()
permission_classes = [IsAuthenticated] # every class in the list must passPermission classes answer "may they?" using only `request.user` — they run before any object is fetched, so none of them can express ownership. The list is AND: every class must pass. `IsAdminUser` means `is_staff`, not superuser. The out-of-the-box default is `AllowAny`, so set `DEFAULT_PERMISSION_CLASSES` to `IsAuthenticated` and open endpoints deliberately.