🛠️ Django 后端架构开发:JWT 项目实践与Drf版本控制
📌 JWT 项目实践:从理论到实战
JSON Web Token(JWT)是当前最流行的身份认证机制之一,在后端开发中被广泛使用。它基于Token的身份验证方式,避免了传统的Session认证在分布式系统中的局限性。在本节中,我们将通过一个实际的Django项目,详细解析JWT的应用场景和实现方式。
首先,在Django中使用JWT进行用户认证时,通常需要借助第三方库,如 djangorestframework-jwt
或 django-rest-framework-simplejwt
。这些库提供了方便的工具和方法,帮助我们在Django REST Framework中集成JWT。
以下是一个简单的项目示例,我们将逐步解析其中的关键代码。
# settings.py 配置 INSTALLED_APPS = [ ... 'rest_framework', 'rest_framework_simplejwt', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ), } # 配置JWT的过期时间等参数 SIMPLE_JWT = { 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), 'ROTATE_REFRESH_TOKENS': True, 'BLACKLIST_AFTER_ROTATION': True, 'ALGORITHM': 'HS256', 'SIGNING_KEY': SECRET_KEY, 'VERIFYING_KEY': None, 'AUTH_HEADER_TYPES': ('Bearer',), ... }
在 settings.py
中,我们配置了JWT的认证方式,并设置了相关参数。ACCESS_TOKEN_LIFETIME
是访问令牌的有效时间,而 REFRESH_TOKEN_LIFETIME
则决定了刷新令牌的有效期。这些参数的设置直接影响了系统的安全性和用户体验。
接下来,我们在 views.py
中实现JWT的登录逻辑。
from rest_framework_simplejwt.views import TokenObtainPairView from rest_framework_simplejwt.tokens import RefreshToken from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.decorators import api_view, permission_classes @api_view(['POST']) def login(request): """ 用户登录视图,使用JWT进行身份验证 """ serializer = TokenObtainPairView.as_view()(request._request).data return Response(serializer) @api_view(['POST']) @permission_classes([IsAuthenticated]) def logout(request): """ 用户注销视图,废弃当前的Refresh Token """ try: token = request.data['refresh'] token_obj = RefreshToken(token) token_obj.blacklist() return Response({'message': '注销成功'}, status=200) except Exception as e: return Response({'error': str(e)}, status=400)
在这个示例中,我们创建了 login
和 logout
视图。login
视图通过 TokenObtainPairView
生成访问令牌和刷新令牌,logout
视图则通过黑名单机制废弃用户的刷新令牌,确保其后续的请求失效。
通过这种方式,我们实现了一个基于JWT的完整认证流程,并且支持令牌的手动废弃,提升了系统的安全性。
📌 JWT 使用方式和特点:灵活且高效的认证机制
JWT的全称是JSON Web Token,是一种开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式用于通信双方之间以JSON对象的形式传递信息。该信息通过数字签名进行验证,从而确保数据的真实性与完整性。JWT的应用场景广泛,尤其在现代Web应用中,因其无状态、跨域支持等优点,广受欢迎。
与传统的Session认证机制不同,JWT的无状态性使其非常适合于微服务架构和分布式系统。在传统的Session认证中,服务器需要保存每个用户的Session数据,这在分布式环境下会带来很多挑战。而JWT的自包含性允许服务器不必保存会话状态,极大地减轻了服务器的负担。
JWT的结构包括三部分:头部(Header)、载荷(Payload)和签名(Signature)。
- 头部:头部通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法(如HMAC SHA256或RSA)。
{ "alg": "HS256", "typ": "JWT" }
- 载荷:载荷部分包含声明(claims),声明是一些实体(通常是用户)的状态信息。声明可以分为三类:注册声明(如
iss
、exp
、sub
)、公共声明和私有声明。
{ "sub": "1234567890", "name": "John Doe", "admin": true }
- 签名:签名是将头部、载荷和一个密钥进行编码后生成的。签名部分是保证JWT数据完整性的重要手段,只有拥有密钥的一方才能生成或验证签名。
JWT的使用方式非常简单,通常在用户登录时,服务器会生成一个JWT并返回给客户端,客户端将其保存在本地存储中。在后续的请求中,客户端将JWT放入HTTP请求头中,服务器通过验证JWT的签名来判断请求是否合法。
# 示例:在请求头中携带JWT import requests headers = { 'Authorization': 'Bearer <your_jwt_token_here>', } response = requests.get('https://example.com/api/resource', headers=headers)
这种无状态的认证机制,使得JWT特别适合跨域认证以及微服务架构的系统。客户端不需要每次请求都与服务器进行会话状态的校验,极大地提升了系统的性能。
📌 REST Framework-JWT 介绍和使用:集成与扩展
Django REST Framework(DRF)提供了强大的身份验证机制,而 djangorestframework-jwt
或 django-rest-framework-simplejwt
则进一步扩展了DRF,方便我们集成JWT。
rest_framework_simplejwt
是一个简单易用的JWT扩展库,它能够轻松地与DRF集成,并提供了丰富的配置选项和自定义功能。在本节中,我们将通过实际代码演示如何在DRF中集成JWT认证,并进行扩展以满足项目需求。
首先,我们在项目中安装并配置 rest_framework_simplejwt
。
pip install djangorestframework-simplejwt • 1
安装完成后,我们在 settings.py
中进行配置,指定默认的认证类为 JWTAuthentication
。
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ), }
接下来,我们创建自定义的视图和路由,以支持JWT的生成和刷新。
# urls.py 配置 from django.urls import path 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'), ]
在这个配置中,我们创建了两个路由,一个用于获取初始的访问令牌和刷新令牌,另一个用于刷新访问令牌。这种机制确保了令牌在过期后可以通过刷新令牌获取新的访问令牌,而不需要重新登录。
为了增强项目的安全性,我们还可以自定义 TokenObtainPairSerializer
,以加入额外的用户信息到JWT载荷中。
# serializers.py from rest_framework_simplejwt.serializers import TokenObtainPairSerializer class CustomTokenObtainPairSerializer(TokenObtainPairSerializer): def validate(self, attrs): data = super().validate(attrs) data['username'] = self.user.username data['email'] = self.user.email return data
然后在视图中使用我们自定义的序列化器。
from rest_framework_simplejwt.views import TokenObtainPairView class CustomTokenObtainPairView(TokenObtainPairView): serializer_class = CustomTokenObtainPairSerializer
通过这种方式,我们可以将更多的用户信息嵌入到JWT中,满足项目的具体需求。
📌 REST Framework 身份验证和权限管理:安全与灵活性的完美结合
在构建Web API时,身份验证和权限管理是不可忽视的重要环节。Django REST Framework(DRF)为我们提供了灵活且强大的身份验证与权限管理机制。通过合理配置和扩展,我们可以确保API的安全性,并实现精细化的权限控制。
1. 身份验证
在DRF中,身份验证是通过设置 DEFAULT_AUTHENTICATION_CLASSES
来实现的。常见的身份验证方式包括Session、Token、JWT等。在本节中,我们将重点讨论JWT的身份验证。
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES ': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ), }
通过上述配置,DRF将使用JWT进行身份验证。每次API请求时,DRF会从请求头中提取JWT,并验证其有效性。若验证通过,则请求将继续处理,否则返回401未授权错误。
2. 权限管理
DRF的权限管理机制允许我们根据请求用户的身份、请求方法、请求资源等条件,精细控制访问权限。DRF提供了多种内置权限类,如 AllowAny
、IsAuthenticated
、IsAdminUser
和 IsAuthenticatedOrReadOnly
等。
例如,我们可以使用 IsAuthenticated
权限类,确保只有经过身份验证的用户才能访问某些敏感资源。
from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView from rest_framework.response import Response class SecureAPIView(APIView): permission_classes = [IsAuthenticated] def get(self, request): return Response({'message': '只有认证用户可以看到这条信息'})
此外,我们还可以自定义权限类,以满足特定的业务需求。例如,我们可以创建一个 IsOwner
权限类,确保只有资源的所有者才能对其进行修改。
from rest_framework.permissions import BasePermission class IsOwner(BasePermission): """ 只允许资源的所有者进行操作 """ def has_object_permission(self, request, view, obj): return obj.owner == request.user
在视图中,我们可以将自定义权限类与其他权限类组合使用,以实现复杂的权限控制逻辑。
class UserDetailAPIView(APIView): permission_classes = [IsAuthenticated, IsOwner] def get(self, request, pk): user = get_object_or_404(User, pk=pk) self.check_object_permissions(request, user) return Response({'username': user.username, 'email': user.email})
通过上述配置,我们可以确保只有资源所有者本人才能查看或修改其个人信息,提升了系统的安全性和用户体验。
📌 REST Framework 版本控制 - URLPathVersioning、QueryParameterVersioning 和 NamespaceVersioning:灵活应对API演化
在API开发中,随着业务的发展和用户需求的变化,API的版本控制变得尤为重要。Django REST Framework(DRF)提供了多种版本控制策略,包括 URLPathVersioning
、QueryParameterVersioning
和 NamespaceVersioning
,帮助我们灵活应对API的演化。
1. URLPathVersioning
URLPathVersioning
是一种将版本号嵌入到URL路径中的版本控制方式。例如,/api/v1/resource/
和 /api/v2/resource/
分别对应API的第一个版本和第二个版本。
我们可以在 settings.py
中配置默认的版本控制类为 URLPathVersioning
。
REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning', 'DEFAULT_VERSION': 'v1', 'ALLOWED_VERSIONS': ['v1', 'v2'], }
然后,在 urls.py
中配置路径版本号。
from django.urls import path from .views import ResourceAPIView urlpatterns = [ path('api/v1/resource/', ResourceAPIView.as_view(), name='resource_v1'), path('api/v2/resource/', ResourceAPIView.as_view(), name='resource_v2'), ]
通过这种方式,客户端可以通过指定不同的URL路径来访问不同版本的API。
2. QueryParameterVersioning
QueryParameterVersioning
是另一种常见的版本控制策略,它通过在请求URL中添加查询参数来指定API版本。例如,/api/resource/?version=1
和 /api/resource/?version=2
分别对应API的第一个版本和第二个版本。
在 settings.py
中配置 QueryParameterVersioning
。
REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.QueryParameterVersioning', 'DEFAULT_VERSION': 'v1', 'ALLOWED_VERSIONS': ['v1', 'v2'], 'VERSION_PARAM': 'version', }
通过这种方式,客户端可以通过在请求URL中指定查询参数来选择所需的API版本。
3. NamespaceVersioning
NamespaceVersioning
是一种通过URL命名空间来实现API版本控制的策略。它允许我们为不同版本的API分配不同的URL命名空间,从而实现版本隔离。
在 urls.py
中配置命名空间。
from django.urls import path, include urlpatterns = [ path('api/v1/', include(('myapp.urls_v1', 'myapp'), namespace='v1')), path('api/v2/', include(('myapp.urls_v2', 'myapp'), namespace='v2')), ]
在视图中,我们可以通过 reverse
函数或 reverse_lazy
函数生成对应版本的URL。
from django.urls import reverse class SomeAPIView(APIView): def get(self, request): url_v1 = reverse('v1:resource-detail', kwargs={'pk': 1}) url_v2 = reverse('v2:resource-detail', kwargs={'pk': 1}) return Response({'v1_url': url_v1, 'v2_url': url_v2})
这种版本控制方式特别适用于大型项目,通过URL命名空间可以有效管理不同版本的API,并确保版本之间的隔离。
📌 REST Framework 版本控制 - AcceptHeaderVersioning:通过请求头实现版本选择
AcceptHeaderVersioning
是一种通过HTTP请求头中的 Accept
字段来控制API版本的策略。客户端通过在请求头中指定版本信息,来请求不同版本的API。
在 settings.py
中配置 AcceptHeaderVersioning
。
REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning', 'DEFAULT_VERSION': 'v1', 'ALLOWED_VERSIONS': ['v1', 'v2'], 'VERSION_PARAM': 'version', }
然后,客户端可以通过如下方式指定版本信息:
curl -H "Accept: application/vnd.example.v1+json" https://example.com/api/resource/
或
curl -H "Accept: application/vnd.example.v2+json" https://example.com/api/resource/
通过这种方式,API的版本信息直接嵌入到请求头中,提升了请求URL的可读性,并且有助于保持URL的简洁。