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

如何在Django中限制媒体文件(Media-File)的访问权限?

解决Django私有视频文件的访问权限限制问题

要解决「拿到URL就能直接访问视频」的问题,核心是让视频文件的请求必须经过Django的权限校验,而不是直接通过Web服务器(Nginx/Apache)对外暴露。以下是具体实现步骤:

1. 调整文件存储位置

将视频文件从默认的MEDIA_ROOT(通常配置为可直接访问的目录)移到无法被Web服务器直接访问的私有目录,比如项目根目录下的private_media:

# settings.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# 原公开媒体配置保留(如果有其他公开文件)
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

# 新增私有媒体配置
PRIVATE_MEDIA_ROOT = os.path.join(BASE_DIR, 'private_media')
PRIVATE_MEDIA_URL = '/private-media/'

同时修改你的视频模型,指定upload_to到私有目录下的子路径:

# models.py
from django.db import models
from django.contrib.auth.models import User

class Video(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    file = models.FileField(upload_to='videos/')  # 文件会存在 private_media/videos/ 下
    # 其他字段...

2. 编写权限校验的文件服务视图

创建一个视图,负责接收视频请求、验证用户权限,然后返回文件内容。这里提供两种实现方式:

函数视图版本

# views.py
from django.http import FileResponse, Http404
from django.contrib.auth.decorators import login_required
from .models import Video

@login_required
def serve_private_video(request, video_id):
    # 检查视频是否存在
    try:
        video = Video.objects.get(id=video_id)
    except Video.DoesNotExist:
        raise Http404("视频不存在")
    
    # 验证当前用户是否为所有者
    if video.owner != request.user:
        raise Http404("你没有权限访问该视频")
    
    # 返回视频文件,设置正确的Content-Type
    video_file = open(video.file.path, 'rb')
    response = FileResponse(video_file)
    response['Content-Type'] = 'video/mp4'
    return response

类视图版本(更符合Django通用视图风格)

# views.py
from django.views.generic import DetailView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import Http404, FileResponse
from .models import Video

class PrivateVideoServeView(LoginRequiredMixin, DetailView):
    model = Video

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        # 权限校验
        if self.object.owner != request.user:
            raise Http404("你没有权限访问该视频")
        
        # 返回文件
        video_file = open(self.object.file.path, 'rb')
        response = FileResponse(video_file)
        response['Content-Type'] = 'video/mp4'
        return response

3. 配置路由映射

将私有媒体的请求指向上面的视图:

# urls.py
from django.urls import path
from .views import serve_private_video, PrivateVideoServeView

urlpatterns = [
    # 函数视图路由
    path('private-media/video/<int:video_id>/', serve_private_video, name='serve_private_video'),
    # 类视图路由(二选一)
    # path('private-media/video/<int:pk>/', PrivateVideoServeView.as_view(), name='serve_private_video'),
]

4. 修改模板中的视频链接

把原来直接指向video.file.url的src,替换为权限视图的URL:

<!-- 模板文件 -->
<video controls>
    <source src="{% url 'serve_private_video' video.id %}" type="video/mp4">
    你的浏览器不支持视频播放
</video>

5. 优化大文件传输(可选)

如果视频文件较大,直接用FileResponse会占用Django进程资源,推荐使用django-sendfile2库让Web服务器直接发送文件(仅权限校验由Django完成):

  1. 安装库:pip install django-sendfile2
  2. 配置settings(以Nginx为例):
# settings.py
SENDFILE_BACKEND = 'sendfile.backends.xsendfile'
SENDFILE_ROOT = PRIVATE_MEDIA_ROOT
SENDFILE_URL = PRIVATE_MEDIA_URL
  1. 修改视图:
# views.py
from sendfile import sendfile

@login_required
def serve_private_video(request, video_id):
    try:
        video = Video.objects.get(id=video_id)
    except Video.DoesNotExist:
        raise Http404("视频不存在")
    
    if video.owner != request.user:
        raise Http404("你没有权限访问该视频")
    
    return sendfile(request, video.file.path, attachment=False, mimetype='video/mp4')

同时需要在Nginx配置中添加对X-Accel-Redirect的支持,确保私有目录不会被直接访问。

内容的提问来源于stack exchange,提问作者jefferson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 11:15:34