Python 限制对Django中私有文件下载的访问

Python 限制对Django中私有文件下载的访问,python,django,django-file-upload,Python,Django,Django File Upload,我的django应用程序中有多个文件字段,它们可以属于不同的用户。 我正在寻找一种好方法来限制非文件所有者用户对文件的访问 实现这一目标的最佳方式是什么?有什么想法吗?通常,您不会通过Apache、Nginx或您正在使用的任何web服务器直接提供的普通静态文件来路由私有文件。而是编写一个定制的Django视图,该视图处理权限检查,然后将文件作为流式下载返回 确保文件位于特殊的私人文件夹中,并且不会通过Django的媒体URL或静态URL 写一个视图,它将 检查用户是否有权访问视图逻辑中的文件

我的django应用程序中有多个文件字段,它们可以属于不同的用户。 我正在寻找一种好方法来限制非文件所有者用户对文件的访问


实现这一目标的最佳方式是什么?有什么想法吗?

通常,您不会通过Apache、Nginx或您正在使用的任何web服务器直接提供的普通静态文件来路由私有文件。而是编写一个定制的Django视图,该视图处理权限检查,然后将文件作为流式下载返回

  • 确保文件位于特殊的私人文件夹中,并且不会通过Django的
    媒体URL
    静态URL

  • 写一个视图,它将

    • 检查用户是否有权访问视图逻辑中的文件

    • 使用Python的
      Open()

    • 返回HTTP响应,该响应获取文件句柄作为参数
      HTTP.HttpResponse(\u file,content\u type=“text/plain”)


例如,请参见
download()

不幸的是@Mikko的解决方案实际上无法在生产环境中工作,因为django不是为文件服务而设计的。在生产环境中,文件需要由HTTP服务器(如apache、nginx等)提供服务,而不是由应用程序/django服务器(如uwsgi、gunicorn、mod_wsgi等)提供服务

这就是为什么限制文件访问不是很容易的原因:您需要一种方式让HTTP服务器询问应用程序服务器是否可以将文件提供给请求它的特定用户。正如您所理解的,这需要对应用程序和http服务器进行修改

上述问题的最佳解决方案是django sendfile(),它使用X-sendfile机制来实现上述功能。我从项目描述中复制:

这是一个包装器,用于将文件发送到web客户端的特定于web服务器的方法。当Django需要检查与文件相关的权限,但不希望为文件本身的实际字节提供服务时,这非常有用。i、 e.Django并不是为大文件服务的

要了解有关senfile机制的更多信息,请阅读以下答案:


2018更新:请注意,django sendfile似乎不再被维护;也许它仍然可以工作,但是如果你想要一个具有类似功能的更现代的软件包,请看一下commenter@surfer190的建议。尤其要确保您实现了“优化大型文件传输”部分;实际上,所有传输都需要此功能,而不仅仅是大型文件。

如果您只需要中等安全性,我的方法如下:

1) 当用户上传文件时,为其生成一个难以猜测的路径。例如,您可以为/static文件夹中的每个上载文件创建一个具有随机生成的名称的文件夹。您只需使用以下示例代码即可完成此操作:

file_path = "/static/" + os.urandom(32).encode('hex') + "/" + file_name
这样,很难猜测其他用户的文件存储在哪里

2) 在数据库中,将所有者链接到文件。示例模式可以是:

上传(id、用户id、文件路径)

3) 使用模型中文件字段的属性来限制对文件的访问,方法如下:

class YourModel(models.Model)
    _secret_file = models.FileField()

    def get_secret_file(self):
        # check in db if the user owns the file
        if True:
            return self._secret_file
        elif:
            return None # or something meaningful depanding on your app

    secret_file = property(get_secret_file)

这最好由服务器来处理,例如nginx(nginx必须使用
--with-http\u secure\u link\u模块编译)

文档中的示例:

location /some-url/ {
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr some-secret";

    if ($secure_link = "") {
        return 403;
    }

    if ($secure_link = "0") {
        return 410;
    }

    if ($secure_link = "1") {
        // authorised...
    }
}
该文件的访问方式如下:

/some-url/some-file?md5=_e4Nc3iduzkWRm01TBBNYw&expires=2147483647
(这既有时间限制,也受该IP地址的用户的约束)

生成要传递给用户的令牌将使用以下方法:

echo -n 'timestamp/some-url/some-file127.0.0.1 some-secret' | \
openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =

我建议您遵循,但您必须实现自己的方法来限制其他用户不访问。。。!尽管如此,django sendfile是一个很好的包。如果您使用@surfer190,那么定制代码就更少了。您提到的包现在看起来是一个很好的解决方案,因为django sendfile似乎不再维护了:(我将更新答案,使其也包含此包。但是请注意,当我第一次回答问题时,django私有存储实际上并不存在!