Django REST Framework: 构建带有自定义认证的API
在本文中,我们将探讨如何使用Django和Django REST Framework (DRF)构建一个带有自定义认证的API。我们将涵盖从项目设置到处理常见陷阱的整个过程,包括自定义用户模型、序列化器、视图函数、URL配置以及必要的设置。
1. 项目设置
首先,在PyCharm中创建一个新的Django项目(不挂魔法可能会卡死)。然后,使用以下命令创建一个用户管理app:
python manage.py startapp account
2. 模型设计
在account/models.py
中,创建一个自定义用户模型:
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
is_admin = models.BooleanField(default=False)
创建这个自定义用户模型后,确保在 settings.py
中设置 AUTH_USER_MODEL
(我们将在后面的设置部分详细说明)。
3. 序列化器
在account/serializers.py
中,创建一个用户序列化器:
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['id', 'username', 'email', 'password', 'is_admin']
def create(self, validated_data):
return User.objects.create_user(**validated_data)
4. 自定义权限装饰器
在account/decorators.py
中,创建一个管理员权限装饰器:
from functools import wraps
from django.http import JsonResponse
def admin_required(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
if request.user.is_authenticated and request.user.is_admin:
return view_func(request, *args, **kwargs)
else:
return JsonResponse({'error': 'Admin privileges required'}, status=403)
return wrapper
5. 自定义认证类
在account/authentication.py
中,创建一个禁用CSRF检查的认证类(具体原因请看’注意事项和常见陷阱’第六点):
from rest_framework.authentication import SessionAuthentication
class CsrfExemptSessionAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return # 禁用CSRF检查
6. 视图
在account/views.py
中,创建视图函数:
from django.contrib.auth import authenticate, login
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.response import Response
from rest_framework import status
from .models import User
from .serializers import UserSerializer
from .decorators import admin_required
from .authentication import CsrfExemptSessionAuthentication
from rest_framework.permissions import IsAuthenticated, AllowAny
@api_view(['GET'])
@authentication_classes([CsrfExemptSessionAuthentication])
@permission_classes([IsAuthenticated])
@admin_required
def user_list(request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
@api_view(['POST'])
@permission_classes([AllowAny])
def register(request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([AllowAny])
def login_view(request):
username = request.data.get('username')
password = request.data.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
serializer = UserSerializer(user)
return Response(serializer.data)
return Response({'error': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED)
7. URL配置
在account/urls.py
中,配置URL:
from django.urls import path
from . import views
urlpatterns = [
path('users/', views.user_list, name='user-list'),
path('register/', views.register, name='register'),
path('login/', views.login_view, name='login'),
]
在主项目的urls.py
中,包含account app的URLs:
from django.urls import path, include
urlpatterns = [
path('api/account/', include('account.urls')),
]
8. 设置文件配置
在settings.py
中,进行必要的配置:
INSTALLED_APPS = [
# ... 其他应用 ...
'rest_framework',
'corsheaders',
'account',
]
AUTH_USER_MODEL = 'account.User'
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'account.authentication.CsrfExemptSessionAuthentication',
],
}
# CORS设置
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000", # 前端开发服务器地址
"http://127.0.0.1:3000",
]
CORS_ALLOW_CREDENTIALS = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'your-backend-ip']
AUTH_USER_MODEL = 'accounts.User'
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # 确保这是第一个中间件
# ... 其他中间件 ...
# 'django.middleware.csrf.CsrfViewMiddleware', # 注释掉这行
]
注意事项和常见陷阱
-
CORS设置: 当使用session认证时,不能将CORS设置为允许所有源(
CORS_ALLOW_ALL_ORIGINS = True
)。必须明确指定允许的源。 -
ALLOWED_HOSTS: 确保将后端服务器的IP地址添加到
ALLOWED_HOSTS
列表中。 -
中间件顺序:
corsheaders.middleware.CorsMiddleware
应该是中间件列表中的第一项,以确保它能够正确处理CORS头。 -
AUTH_USER_MODEL 设置: 当使用自定义用户模型时,必须在
settings.py
中设置AUTH_USER_MODEL = 'account.User'
。这个设置告诉 Django 使用您的自定义用户模型,而不是默认的用户模型。重要的是要在项目的早期就设置这个,最好是在进行首次数据库迁移之前。如果在项目后期更改这个设置,可能会导致复杂的数据库迁移问题。 -
CSRF中间件: 如果你使用
CsrfExemptSessionAuthentication
,你应该注释掉django.middleware.csrf.CsrfViewMiddleware
。这没有任何实际作用,只不过让后端不会向前端发送无意义的csrfkey。 -
关于自定义认证类: 因为Django安全第一的设计理念,开启sessionkey时会自动开启csrf认证,因此必须要覆写掉csrf的认证函数才能实现只使用sessionkey进行认证。当然,如果你不在意的话,可以直接用自带的’SessionAuthentication’。
评论区