You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 10:57:01