Django REST Framework (DRF) 提供了强大而灵活的认证系统,能够满足各种API安全需求。本文将全面介绍DRF中的认证机制,包括基本配置、常用认证方式以及高级定制方法。
一、DRF认证基础
1. 认证与权限的区别
在开始之前,需要明确两个重要概念:
- 认证(Authentication):验证用户身份(你是谁)
- 权限(Permission):确定用户能做什么(你能访问什么)
本文重点讲解认证系统的配置与使用。
2. 默认认证设置
DRF的默认认证设置在settings.py
中配置:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
]
}
二、内置认证方案
DRF提供了多种内置认证方式,适用于不同场景。
1. Session认证
适用于前端与Django后端在同一域名下的情况(如传统web应用)。
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
]
}
特点:
- 使用Django的session后端
- 需要CSRF保护(前端需要包含CSRF token)
2. Basic认证
简单的HTTP基本认证,适合测试环境但不推荐生产使用。
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
]
}
特点:
- 用户名密码通过Base64编码传输
- 不安全,除非配合HTTPS使用
3. Token认证
简单的基于令牌的认证(DRF内置)。
INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}
使用流程:
- 运行
python manage.py migrate
创建token表 - 为用户创建token:
from rest_framework.authtoken.models import Token
token = Token.objects.create(user=user)
print(token.key)
- 客户端在请求头中添加:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
4. JSON Web Token (JWT) 认证
更现代的基于JWT的认证,需要安装第三方包。
安装配置
pip install djangorestframework-simplejwt
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
]
}
添加路由
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
...
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
客户端使用
- 获取token:
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' \
http://localhost:8000/api/token/
返回示例:
{
"access": "eyJhbGciOiJIUz...",
"refresh": "eyJhbGciOiJIUz..."
}
- 访问API:
Authorization: Bearer eyJhbGciOiJIUz...
三、自定义认证方案
当内置认证不能满足需求时,可以创建自定义认证类。
1. 基本自定义认证类结构
from rest_framework import authentication
from rest_framework import exceptions
class CustomAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
# 获取认证凭证
auth_header = request.META.get('HTTP_X_CUSTOM_AUTH')
if not auth_header:
return None # 不认证,交给下一个认证类处理
try:
# 验证逻辑
user = self.validate_token(auth_header)
except InvalidToken:
raise exceptions.AuthenticationFailed('Invalid token')
return (user, None) # 返回(user, auth)元组
def validate_token(self, token):
# 实现你的验证逻辑
...
2. API Key认证示例
class APIKeyAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
api_key = request.META.get('HTTP_X_API_KEY') or request.GET.get('api_key')
if not api_key:
return None
try:
user = User.objects.get(apikey__key=api_key)
except (User.DoesNotExist, APIKey.DoesNotExist):
raise exceptions.AuthenticationFailed('Invalid API key')
return (user, None)
3. 混合认证示例
class HybridAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
# 尝试JWT认证
jwt_auth = JWTAuthentication()
try:
return jwt_auth.authenticate(request)
except exceptions.AuthenticationFailed:
pass
# 尝试API Key认证
api_key_auth = APIKeyAuthentication()
try:
return api_key_auth.authenticate(request)
except exceptions.AuthenticationFailed:
pass
# 所有认证方式都失败
return None
四、认证策略最佳实践
1. 生产环境推荐配置
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
2. 视图级别的认证设置
可以在视图级别覆盖全局认证设置:
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
...
3. 认证性能优化
- 对于频繁验证的JWT,考虑使用缓存
- 限制认证尝试次数防止暴力破解
- 使用无状态认证减少数据库查询
from django.core.cache import cache
class CachedJWTAuthentication(JWTAuthentication):
def authenticate(self, request):
# 先从缓存获取用户
user = self.get_cached_user(request)
if user:
return (user, None)
# 缓存未命中,走正常认证流程
return super().authenticate(request)
def get_cached_user(self, request):
auth_header = request.META.get('HTTP_AUTHORIZATION')
if not auth_header:
return None
try:
prefix, token = auth_header.split()
if prefix.lower() != 'bearer':
return None
user_id = cache.get(f'jwt_user_{token}')
if user_id:
return User.objects.get(id=user_id)
except:
return None
五、常见问题解决方案
1. CSRF与Session认证
当使用Session认证时,需要处理CSRF保护:
// 前端示例:获取CSRF token
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
// 在请求头中添加
fetch('/api/endpoint/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken
},
body: JSON.stringify(data)
})
2. 处理过期token
对于JWT,可以配置简单的过期处理:
# settings.py
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
}
3. 多类型用户认证
处理不同类型的用户(如普通用户、管理员、第三方应用):
class MultiUserAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
# 尝试JWT认证
try:
jwt_auth = JWTAuthentication()
user, _ = jwt_auth.authenticate(request)
if user and user.is_active:
return (user, None)
except:
pass
# 尝试API Key认证(第三方应用)
try:
api_auth = APIKeyAuthentication()
user, _ = api_auth.authenticate(request)
if user and user.is_service_account:
return (user, None)
except:
pass
return None
六、安全注意事项
- 始终使用HTTPS:特别是在生产环境中传输认证凭证
- 合理设置token过期时间:平衡安全性与用户体验
- 保护敏感端点:关键操作应要求重新认证
- 实现速率限制:防止暴力破解攻击
- 定期轮换密钥:特别是JWT的签名密钥
通过本文的介绍,你应该已经掌握了Django REST Framework中各种认证方式的配置和使用方法。根据你的应用场景选择合适的认证策略,并始终牢记安全最佳实践,才能构建出既安全又好用的API服务。