繁体   English   中英

如何生成Django一次性下载链接

[英]How to generate a Django one-time download link

我想保护我的项目中的可下载文件,但不知道如何实现。 每次 post_detail 视图被调用时,都会生成一个新的下载链接,有效期为 60 分钟,并且也只能是访问链接。

模型.py

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(verbose_name="Post Title", max_length=25)
    content = models.TextField(verbose_name="Post Content", max_length=5000)
    tag = models.CharField(verbose_name="Tags/Meta - (sep. by comma)", max_length=50, blank=True)
    category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE, null=True)
    postattachment = fields.FileField(
        verbose_name="Post Attachment",
        blank=True,
        null=True,
        upload_to=get_file_path_user_uploads,
        validators=[file_extension_postattachment, file_size_postattachment]

    published_date = models.DateField(auto_now_add=True, null=True)


    def publish(self):
        self.published_date = timezone.now()
        self.save()

    class Meta:
        verbose_name = "Post"
        verbose_name_plural = "Post(s)"
        ordering = ['-title']

    def __str__(self):
        return self.title

视图.py

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    list_comments = Comment.objects.get_queryset().filter(post_id=pk).order_by('-pk')
    paginator = Paginator(list_comments, 10)
    page = request.GET.get('commentpage')
    comments = paginator.get_page(page)
    return render(request, 'MyProject/post_detail.html', {'post': post, 'comments': comments})

如果 smb。 也许有一些练习示例它会非常有帮助。

提前致谢

我不是 Django 专家,但我认为这是纯粹在 Django 中无法实现的。 一旦你的请求在 Django 中被执行,也就是说,你已经成功地为你的用户生成了一个下载链接,你不能在 60 分钟后返回并使其失效。 不是纯 Django(修复我!)。

另一个阻塞原因是 Django 根本就不是为提供文件而设计的。 文件(静态和媒体)旨在由您在 Django 前面的网络服务器(apache/nginx/etc...)提供服务。 例如,可以通过如下链接访问 Django 存储的文件: https://my-django-app.venom.com/media/my_file.jpg : https://my-django-app.venom.com/media/my_file.jpg

这里的问题是,您的文件的位置很容易被猜到。 为了更难猜测,你应该把它放在一个随机长字符串的文件夹中,像这样: https://my-django-app.venom.com/media/b926yqagf6qrzpyew7h3kghtejayxp/my_file.jpg : https://my-django-app.venom.com/media/b926yqagf6qrzpyew7h3kghtejayxp/my_file.jpg

为了实现这样的功能,我看到了两种方法(可能有几十种其他选择,但我立即想到了这两种):

生成和删除随机路径

要在 60 分钟后使路径无效,您必须按顺序对每个文件请求执行以下操作:

  1. 生成随机字符串
  2. 使用生成的随机字符串作为名称创建一个文件夹
  3. 将要提供的文件复制到该文件夹​​中(该文件的原始版本应存储在您的MEDIA文件夹之外以提高安全性
  4. 向用户展示生成链接
  5. 在某处注册此 URL 并为其设置到期日期,例如,从生成起 60 分钟(我会为此创建一个简单的模型并将其存储在 SQL 中)
  6. 每分钟在存储的 URL 上运行一个作业,如果它已过期,则从文件系统中删除其文件夹

要实现第 6 步,您必须使用 Celery 扩展您的 Django 应用程序。 使用 Celery,您可以轻松安排作业(google for celery-beat )。 此作业将每分钟执行一次(或您喜欢的任何时间),查询当前时间之后存储的 URL,并从文件系统上的MEDIA文件夹中删除随机字符串文件夹及其内容。 Celery 超级简单,网上有几十个很好的例子。

使用对象存储服务器管理 Django 之外的过期链接

通过将用户上传的内容存储在对象存储(例如 minio)中,可以非常轻松地在基础架构级别管理到期链接。 Minio 与 Amazon S3 非常相似,但它是开源的,可以托管在您自己的场所。 Minio 可以为存储的文件生成链接,您可以将过期时间设置在 1 分钟到 1 周之间。 在 Django 中,您所要做的就是从 minio 请求链接并指定到期时间。 其余的由 minio 管理。

要实现这种方法,您必须扩展 Django 的文件存储 API ( https://docs.djangoproject.com/en/2.1/ref/files/storage/ ) 并使用为 Django 编写的 minio 客户端之一。 我推荐 django-minio-storage ( https://github.com/py-pa/django-minio-storage )。

如果您采用这种方法,您可以将 Django 与用户上传的内容完全分离,并停止依赖您的网络服务器从 Django 的MEDIA文件夹中提供文件。

祝你好运!

2021 年更新:

自从我上次更新以来,我已经创建了自己的 Django StorageBackend 实现来轻松地与 MinIO 交互。 我尽我所能保持这个库是最新的,但总是欢迎拉取请求: https : //github.com/theriveman/django-minio-backend

你可以查看这个 pypi 包django-onetimelink 它可以创建一个站点,其中包含所有上传文件的一次性链接。 它可用于从上传的文件生成一次性链接。

如果您需要一次性链接,

  1. 使用 pk(传递值的能力)创建一个 django url。
  2. 创建一组列表哈希并将它们存储在数据库中。
  3. 编写一个接受 pk 并使用可用哈希列表检查它的视图,如果检查通过,则向用户提供可下载的文件,延迟 celery 任务以删除文件(一段时间后)并从列表中删除哈希以避免将来使用. 否则如果检查失败重定向 url 错误页面。
  4. 应向用户提供只能使用一次的未使用哈希。

希望你明白了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM