如何在Django Rest Framework中基于JWT实现静态图片访问鉴权
DRF静态图片资源JWT鉴权实现方案
Django默认的静态文件服务不会做业务权限校验,且生产环境通常不会用Django直接承载静态资源,你可以按以下步骤实现需求:
1. 调整资源访问路由,接管图片请求
不要将私有图片放在默认的static目录,建议单独存放在media/private_images目录下,新增自定义路由匹配私有图片请求,替换原有的静态资源路径:
# urls.py from django.urls import path from .views import PrivateImageView urlpatterns = [ # 其余业务路由 path("private/images/<str:image_name>", PrivateImageView.as_view(), name="private-image"), ]
调整用户资料接口返回的图片URL为BASE_URL/private/images/ABC.jpg,不再使用原静态路径。
2. 实现带鉴权的自定义图片视图
使用DRF的APIView搭配JWT认证类,加入业务权限校验逻辑:
# views.py from rest_framework.views import APIView from rest_framework.permissions import IsAuthenticated from rest_framework_simplejwt.authentication import JWTAuthentication from django.http import FileResponse, Http404, HttpResponseForbidden from django.conf import settings import os from .models import UserProfile # 替换为你自己的用户资料模型 class PrivateImageView(APIView): # 开启JWT认证 authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] def get(self, request, image_name): # 查找图片关联的用户资料,根据你的模型存储规则调整查询条件 try: profile = UserProfile.objects.get(avatar=f"private_images/{image_name}") except UserProfile.DoesNotExist: raise Http404("资源不存在") # 自定义权限校验逻辑,示例为仅资料所有者和管理员可访问 if not (request.user.id == profile.user.id or request.user.is_staff): return HttpResponseForbidden("无权限访问该资源") # 校验通过返回图片 image_path = os.path.join(settings.PRIVATE_IMAGE_ROOT, image_name) if not os.path.exists(image_path): raise Http404("资源不存在") return FileResponse(open(image_path, "rb"))
3. 新增私有资源配置
在settings.py中添加私有图片存储路径配置:
import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) PRIVATE_IMAGE_ROOT = os.path.join(BASE_DIR, "media", "private_images")
手动创建对应的存储文件夹,保证服务进程有该目录的读权限。
4. 生产环境性能优化
生产环境建议用Nginx的内部重定向能力处理文件返回,避免Django处理文件IO拖慢服务性能:
- 视图返回部分替换为以下代码,仅做权限校验后返回重定向头:
response = HttpResponse() response["Content-Type"] = "" # 让Nginx自动判断资源类型 response["X-Accel-Redirect"] = f"/internal_private_images/{image_name}" return response
- Nginx配置新增内部路由规则,禁止外部直接访问原始存储路径:
location /internal_private_images/ { internal; alias /your/project/path/media/private_images/; }
特殊场景适配
如果用<img>标签加载图片无法携带Authorization请求头,可以自定义JWT认证类支持从查询参数取token:
from rest_framework_simplejwt.authentication import JWTAuthentication from rest_framework.exceptions import AuthenticationFailed class QueryParamJWTAuthentication(JWTAuthentication): def authenticate(self, request): token = request.query_params.get("token") if not token: return super().authenticate(request) try: validated_token = self.get_validated_token(token) except Exception: raise AuthenticationFailed("无效token") return self.get_user(validated_token), validated_token
将视图的authentication_classes替换为该自定义类后,前端可通过BASE_URL/private/images/ABC.jpg?token=用户JWT的格式访问图片。
注意事项
- 私有图片不要存放在默认的
STATIC_ROOT或公开的MEDIA_ROOT目录下,避免被默认静态服务直接暴露 - 如果一张图片关联多个业务资源,调整视图里的资源查询和权限校验逻辑即可
- 生产环境不要使用Django自带的runserver服务,静态资源必须交由Nginx处理
内容的提问来源于stack exchange,提问作者ats-myo
相关产品推荐
相关产品推荐

