DRF chạy 2 lớp trước view: Authentication xác định bạn là ai (set request.user), Permission xác định bạn có được làm hành động này không.
python
# settings.py — default cho toàn project
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated'],
}
# Override per view
class PostViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]Custom permission là class chỉ cần 1-2 method:
python
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.author_id == request.user.idDRF gọi has_permission() cho list/create, và has_object_permission() cho retrieve/update/delete một cách tự động.
Hai chỗ dễ vấp: DEFAULT_PERMISSION_CLASSES áp dụng cho mọi viewset không khai báo riêng, nên đặt IsAuthenticated làm default an toàn hơn AllowAny rất nhiều. Và has_object_permission chỉ chạy khi bạn gọi self.get_object() — nếu truy cập obj qua custom method, phải tự gọi self.check_object_permissions(request, obj), không thì lỗi bảo mật lặng lẽ trôi qua.