认证、权限与限流
DRF 在每次请求的 dispatch() 阶段依次执行认证 → 权限 → 限流三道防线,然后才将请求交给视图方法处理。这三个组件均支持全局配置和视图级局部覆盖,且都可以自定义扩展。
认证(Authentication)
认证负责识别"这个请求是谁发的",并将结果赋值到 request.user 和 request.auth。认证失败不会直接拒绝请求(拒绝是权限层的职责),而是将用户标记为匿名用户(AnonymousUser)。
内置认证类
| 认证类 | 说明 |
|---|---|
SessionAuthentication | 基于 Django Session,适合浏览器端(含 CSRF 检查) |
BasicAuthentication | HTTP Basic Auth,用户名/密码 Base64 编码,仅适合开发调试 |
TokenAuthentication | Token 令牌认证,需要 rest_framework.authtoken 应用 |
RemoteUserAuthentication | 委托给 Django REMOTE_USER 中间件 |
全局配置
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
]
}视图级局部覆盖
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView
class MyAPIView(APIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]自定义认证类
继承 BaseAuthentication 并实现 authenticate() 方法。该方法应返回 (user, auth) 元组,或在认证失败时抛出 AuthenticationFailed,或返回 None(表示本认证类放弃,交给下一个)。
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from django.contrib.auth.models import User
class TokenHeaderAuthentication(BaseAuthentication):
"""从自定义请求头 X-Token 中读取 token 并查找用户"""
def authenticate(self, request):
token = request.META.get("HTTP_X_TOKEN")
if not token:
return None # 未携带 token,跳过本认证类
try:
user = User.objects.get(profile__token=token)
except User.DoesNotExist:
raise AuthenticationFailed("无效的 Token")
return (user, token) # request.user = user, request.auth = token注册到 settings 或视图的 authentication_classes 中即可生效。
Token 认证快速配置
DRF 内置了 Token 认证方案,适合前后端分离项目:
# settings.py
INSTALLED_APPS = [
...
'rest_framework.authtoken',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}python manage.py migrate # 创建 authtoken 表为用户生成 Token:
from rest_framework.authtoken.models import Token
token, created = Token.objects.get_or_create(user=user)
print(token.key)客户端在请求头中携带:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b生产项目通常使用 JWT(
djangorestframework-simplejwt)替代内置 Token,支持无状态、自动过期、刷新等特性。权限(Permissions)
权限负责决定"这个用户有没有资格访问这个接口"。在认证确定用户身份后,权限类进行访问控制。
内置权限类
| 权限类 | 说明 |
|---|---|
AllowAny | 允许所有人访问(默认) |
IsAuthenticated | 仅已认证用户可访问 |
IsAdminUser | 仅管理员(is_staff=True)可访问 |
IsAuthenticatedOrReadOnly | 已认证用户可读写;匿名用户只读(GET/HEAD/OPTIONS) |
全局配置
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}视图级局部覆盖
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
class StudentAPIView(APIView):
permission_classes = [IsAuthenticated]自定义权限类
继承 BasePermission 并实现以下方法之一或全部:
has_permission(request, view):控制能否访问视图(列表级)。has_object_permission(request, view, obj):控制能否访问具体数据对象(详情级,需调用get_object()触发)。
from rest_framework.permissions import BasePermission, SAFE_METHODS
class IsOwnerOrReadOnly(BasePermission):
"""只有资源拥有者才能修改/删除,其他人只读"""
def has_object_permission(self, request, view, obj):
# 安全方法(GET, HEAD, OPTIONS)所有人可用
if request.method in SAFE_METHODS:
return True
# 写操作只允许资源的创建者
return obj.owner == request.user
class IsStaffOrCreator(BasePermission):
"""管理员或创建者可写,其他人只读"""
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
return request.user.is_staff or obj.created_by == request.user多个权限类之间是与关系,所有权限类都返回 True 才放行:
permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]限流(Throttling)
限流控制接口的访问频率,防止滥用(如暴力破解、API 爬虫、高并发攻击)。
内置限流类
| 限流类 | 说明 |
|---|---|
AnonRateThrottle | 匿名用户,按 IP 区分,使用 anon 速率 |
UserRateThrottle | 认证用户,按 user ID 区分,使用 user 速率 |
ScopedRateThrottle | 针对视图的命名范围(throttle_scope)单独配置速率 |
全局配置
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day', # 匿名用户每天最多 100 次
'user': '1000/day', # 认证用户每天最多 1000 次
}
}速率格式:次数/周期,周期可以是 second(s)、minute(m)、hour(h)、day(d)。
视图级局部配置
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class LoginView(APIView):
throttle_classes = [UserRateThrottle]按视图范围限流(ScopedRateThrottle)
当不同接口需要不同频率限制时使用 ScopedRateThrottle:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': ['rest_framework.throttling.ScopedRateThrottle'],
'DEFAULT_THROTTLE_RATES': {
'login': '5/minute', # 登录接口:1 分钟最多 5 次
'contacts': '100/hour', # 联系人接口:1 小时最多 100 次
}
}class LoginView(APIView):
throttle_scope = 'login'
class ContactListView(ListAPIView):
throttle_scope = 'contacts'自定义限流类
from rest_framework.throttling import SimpleRateThrottle
class IPRateThrottle(SimpleRateThrottle):
"""按 IP 区分的限流,速率从 settings 中读取 ip 键"""
scope = 'ip'
def get_cache_key(self, request, view):
return self.cache_format % {
'scope': self.scope,
'ident': self.get_ident(request), # 获取客户端 IP
}三者协同工作流程
HTTP 请求
│
▼
dispatch()
│
├─ 认证(authentication_classes)
│ → 设置 request.user / request.auth
│
├─ 权限(permission_classes)
│ → has_permission() 通过?否则 403
│
├─ 限流(throttle_classes)
│ → allow_request() 通过?否则 429
│
▼
视图方法(get / post / put / delete ...)
│
└─ 详情操作:get_object() → has_object_permission()has_object_permission() 只有在视图调用 self.get_object() 时才会触发,直接通过 ORM 查询数据不会执行对象级权限检查。最后更新于