DRF 权限控制 #
一、权限概述 #
1.1 什么是权限 #
权限控制确定已认证用户是否有权执行特定操作,解决"你能做什么"的问题。
text
请求流程
┌─────────────────┐
│ 认证成功 │
│ request.user │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 权限检查 │
│ 你能做什么? │
└────────┬────────┘
│
┌────┴────┐
│ │
▼ ▼
┌───────┐ ┌───────┐
│ 允许 │ │ 拒绝 │
└───────┘ └───────┘
1.2 权限检查时机 #
| 检查点 | 说明 |
|---|---|
| 视图级别 | 检查用户是否有权访问视图 |
| 对象级别 | 检查用户是否有权访问特定对象 |
1.3 内置权限类 #
| 权限类 | 说明 |
|---|---|
| AllowAny | 允许所有用户 |
| IsAuthenticated | 仅认证用户 |
| IsAdminUser | 仅管理员 |
| IsAuthenticatedOrReadOnly | 认证用户可写,其他只读 |
二、内置权限 #
2.1 AllowAny #
允许所有用户访问:
python
from rest_framework.permissions import AllowAny
class ArticleViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
queryset = Article.objects.all()
serializer_class = ArticleSerializer
2.2 IsAuthenticated #
仅认证用户可访问:
python
from rest_framework.permissions import IsAuthenticated
class ArticleViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = Article.objects.all()
serializer_class = ArticleSerializer
2.3 IsAdminUser #
仅管理员可访问:
python
from rest_framework.permissions import IsAdminUser
class UserViewSet(viewsets.ModelViewSet):
permission_classes = [IsAdminUser]
queryset = User.objects.all()
serializer_class = UserSerializer
2.4 IsAuthenticatedOrReadOnly #
认证用户可写,匿名用户只读:
python
from rest_framework.permissions import IsAuthenticatedOrReadOnly
class ArticleViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticatedOrReadOnly]
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def perform_create(self, serializer):
serializer.save(author=self.request.user)
三、自定义权限 #
3.1 创建自定义权限类 #
python
from rest_framework import permissions
class IsOwner(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.owner == request.user
3.2 使用自定义权限 #
python
class ArticleViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, IsOwner]
queryset = Article.objects.all()
serializer_class = ArticleSerializer
3.3 视图级别权限 #
python
class IsAdminOrReadOnly(permissions.BasePermission):
def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True
return request.user and request.user.is_staff
3.4 对象级别权限 #
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 == request.user
四、权限组合 #
4.1 AND组合 #
python
class ArticleViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, IsOwner]
queryset = Article.objects.all()
serializer_class = ArticleSerializer
4.2 OR组合 #
python
from rest_framework.permissions import BasePermission, IsAuthenticated
class IsAdminOrOwner(BasePermission):
def has_object_permission(self, request, view, obj):
return request.user.is_staff or obj.author == request.user
class ArticleViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, IsAdminOrOwner]
queryset = Article.objects.all()
serializer_class = ArticleSerializer
4.3 复杂权限逻辑 #
python
class CanEditArticle(BasePermission):
def has_permission(self, request, view):
return request.user.is_authenticated
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
if request.user.is_staff:
return True
if obj.author == request.user:
return True
if obj.editors.filter(id=request.user.id).exists():
return True
return False
五、动态权限 #
5.1 基于动作的权限 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_permissions(self):
if self.action == 'create':
return [IsAuthenticated()]
if self.action in ['update', 'partial_update', 'destroy']:
return [IsAuthenticated(), IsOwner()]
return [AllowAny()]
5.2 基于HTTP方法的权限 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_permissions(self):
if self.request.method in ['POST', 'PUT', 'PATCH', 'DELETE']:
return [IsAuthenticated(), IsOwner()]
return [AllowAny()]
5.3 基于用户角色的权限 #
python
class RoleBasedPermission(BasePermission):
def has_permission(self, request, view):
required_role = getattr(view, 'required_role', None)
if not required_role:
return True
user_role = getattr(request.user, 'role', None)
return user_role == required_role
class ArticleViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, RoleBasedPermission]
required_role = 'editor'
queryset = Article.objects.all()
serializer_class = ArticleSerializer
六、对象级权限 #
6.1 基本实现 #
python
class IsOwner(BasePermission):
def has_object_permission(self, request, view, obj):
return obj.author == request.user
class ArticleViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, IsOwner]
queryset = Article.objects.all()
serializer_class = ArticleSerializer
6.2 多条件对象权限 #
python
class IsArticleEditable(BasePermission):
message = '您没有权限编辑此文章'
def has_object_permission(self, request, view, obj):
if request.user.is_staff:
return True
if obj.author != request.user:
return False
if obj.status == 'archived':
self.message = '已归档的文章不能编辑'
return False
return True
6.3 检查对象权限 #
python
class ArticleViewSet(viewsets.ModelViewSet):
def update(self, request, *args, **kwargs):
article = self.get_object()
self.check_object_permissions(request, article)
return super().update(request, *args, **kwargs)
七、权限配置 #
7.1 全局配置 #
python
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
7.2 视图级别配置 #
python
class ArticleViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticatedOrReadOnly]
queryset = Article.objects.all()
serializer_class = ArticleSerializer
7.3 函数视图配置 #
python
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def article_list(request):
return Response({'user': request.user.username})
7.4 action级别配置 #
python
from rest_framework.decorators import action
from rest_framework.permissions import IsAdminUser
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
@action(detail=False, permission_classes=[IsAdminUser])
def all(self, request):
articles = self.get_queryset()
serializer = self.get_serializer(articles, many=True)
return Response(serializer.data)
八、权限最佳实践 #
8.1 常用权限组合 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_permissions(self):
if self.action == 'list':
return [AllowAny()]
elif self.action == 'create':
return [IsAuthenticated()]
elif self.action in ['update', 'partial_update', 'destroy']:
return [IsAuthenticated(), IsOwner()]
return [AllowAny()]
8.2 权限消息 #
python
class IsPremiumUser(BasePermission):
message = '此功能仅限高级会员使用'
def has_permission(self, request, view):
return request.user.is_authenticated and request.user.is_premium
8.3 权限缓存 #
python
class CachedPermission(BasePermission):
_cache = {}
def has_permission(self, request, view):
user_id = request.user.id
if user_id not in self._cache:
self._cache[user_id] = self._check_permission(request)
return self._cache[user_id]
def _check_permission(self, request):
return request.user.is_staff
九、实际应用示例 #
9.1 博客系统权限 #
python
class IsAuthorOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
return obj.author == request.user
class IsPublishedOrAuthor(BasePermission):
def has_object_permission(self, request, view, obj):
if obj.is_published:
return True
return obj.author == request.user
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_permissions(self):
if self.action == 'list':
return [AllowAny()]
elif self.action == 'retrieve':
return [IsPublishedOrAuthor()]
elif self.action in ['update', 'partial_update', 'destroy']:
return [IsAuthenticated(), IsAuthorOrReadOnly()]
return [IsAuthenticated()]
9.2 组织权限 #
python
class IsOrganizationMember(BasePermission):
def has_object_permission(self, request, view, obj):
return obj.organization.members.filter(id=request.user.id).exists()
class ProjectViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, IsOrganizationMember]
queryset = Project.objects.all()
serializer_class = ProjectSerializer
十、总结 #
本章学习了DRF权限控制:
- 内置权限:AllowAny、IsAuthenticated等
- 自定义权限:创建自定义权限类
- 权限组合:AND和OR逻辑
- 动态权限:基于动作和方法的权限
- 对象级权限:细粒度访问控制
让我们继续学习JWT认证!
最后更新:2026-03-28